1 /*
2 *----------------------------------------------------------------------------
3 *
4 * msktutil.cpp
5 *
6 * (C) 2004-2006 Dan Perry (dperry@pppl.gov)
7 * (C) 2006 Brian Elliott Finley (finley@anl.gov)
8 * (C) 2009-2010 Doug Engert (deengert@anl.gov)
9 * (C) 2010 James Y Knight (foom@fuhm.net)
10 * (C) 2010-2013 Ken Dreyer <ktdreyer at ktdreyer.com>
11 * (C) 2012-2017 Mark Proehl <mark at mproehl.net>
12 * (C) 2012-2017 Olaf Flebbe <of at oflebbe.de>
13 * (C) 2013-2017 Daniel Kobras <d.kobras at science-computing.de>
14 *
15 This program is free software; you can redistribute it and/or modify
16 it under the terms of the GNU General Public License as published by
17 the Free Software Foundation; either version 2 of the License, or
18 (at your option) any later version.
19
20 This program is distributed in the hope that it will be useful,
21 but WITHOUT ANY WARRANTY; without even the implied warranty of
22 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
23 GNU General Public License for more details.
24
25 You should have received a copy of the GNU General Public License
26 along with this program; if not, write to the Free Software
27 Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
28 *
29 *-----------------------------------------------------------------------------
30 */
31
32 #include "msktutil.h"
33 #ifndef HAVE_STRTOLL
34 #include "strtoll.h"
35 #endif
36 #include <cctype>
37 #include <memory>
38 #include <algorithm>
39
40 /* GLOBALS */
41
42 int g_verbose = 0;
43
44 /* Fatal error */
error_exit(const char * text)45 void error_exit( const char *text) {
46 v_error_exit("error_exit: %s: %s\n", text, strerror(errno));
47 }
48
v_error_exit(const char * format,...)49 void v_error_exit(const char* format, ...) {
50 va_list args;
51 va_start(args, format);
52 vfprintf(stderr, format, args);
53 va_end(args);
54 exit(1);
55 }
56
sform(const char * format,...)57 std::string sform(const char* format, ...)
58 {
59 va_list args;
60 va_start(args, format);
61
62 char *buf;
63 #if !defined(HAVE_VASPRINTF)
64 # ifdef HAVE_VSNPRINTF
65 buf = (char *) malloc(10000);
66 memset(buf, 0, 10000);
67 int result = vsnprintf(buf, 10000-1, format, args);
68 # else
69 # error need either vasprintf or vsnprintf
70 # endif
71 #else
72 int result = vasprintf(&buf, format, args);
73 #endif
74 if (result < 0) {
75 error_exit("vasprintf failed");
76 }
77 std::string outstr(buf, result);
78 free(buf);
79 va_end(args);
80 return outstr;
81 }
82
remove_files_at_exit()83 void remove_files_at_exit()
84 {
85 remove_fake_krb5_conf();
86 remove_ccache();
87 }
88
89
catch_int(int)90 void catch_int(int)
91 {
92 remove_files_at_exit();
93 exit(1);
94 }
95
set_supportedEncryptionTypes(msktutil_flags * flags,char * value)96 void set_supportedEncryptionTypes(msktutil_flags *flags, char * value)
97 {
98 flags->enctypes = VALUE_ON;
99 flags->supportedEncryptionTypes = strtol(value, NULL, 0);
100 }
101
set_cleanup_enctype(msktutil_flags * flags,char * value)102 void set_cleanup_enctype(msktutil_flags *flags, char * value)
103 {
104 int enctype = -1;
105 if (sform(value).compare(sform("des-cbc-crc")) == 0) {
106 enctype = 1;
107 } else if (sform(value).compare(sform("des-cbc-md5")) == 0) {
108 enctype = 3;
109 } else if ((sform(value).compare(sform("arcfour-hmac-md5")) == 0) ||
110 (sform(value).compare(sform("arcfour-hmac")) == 0) ||
111 (sform(value).compare(sform("arcfour")) == 0) ||
112 (sform(value).compare(sform("rc4-hmac-md5")) == 0) ||
113 (sform(value).compare(sform("rc4-hmac")) == 0) ||
114 (sform(value).compare(sform("rc4")) == 0)) {
115 enctype = 23;
116 } else if ((sform(value).compare(sform("aes128-cts-hmac-sha1-96")) == 0) ||
117 (sform(value).compare(sform("aes128-cts-hmac-sha1")) == 0) ||
118 (sform(value).compare(sform("aes128-cts-hmac")) == 0) ||
119 (sform(value).compare(sform("aes128-cts")) == 0) ||
120 (sform(value).compare(sform("aes128")) == 0)) {
121 enctype = 17;
122 } else if ((sform(value).compare(sform("aes256-cts-hmac-sha1-96")) == 0) ||
123 (sform(value).compare(sform("aes256-cts-hmac-sha1")) == 0) ||
124 (sform(value).compare(sform("aes256-cts-hmac")) == 0) ||
125 (sform(value).compare(sform("aes256-cts")) == 0) ||
126 (sform(value).compare(sform("aes256")) == 0)) {
127 enctype = 18;
128 } else {
129 fprintf(stderr,
130 "Error: enctype = %s not supported. "
131 "Supported enctype strings are\n", value
132 );
133 fprintf(stderr, " des-cbc-crc\n");
134 fprintf(stderr, " des-cbc-md5\n");
135 fprintf(stderr, " arcfour\n");
136 fprintf(stderr, " aes128\n");
137 fprintf(stderr, " aes256\n");
138 exit(1);
139 }
140 flags->cleanup_enctype = enctype;
141 }
142
do_verbose()143 void do_verbose()
144 {
145 g_verbose++; /* allow for ldap debuging */
146 }
147
148
qualify_principal_vec(std::vector<std::string> & principals,const std::string & hostname)149 void qualify_principal_vec(std::vector<std::string> &principals,
150 const std::string &hostname)
151 {
152 for(size_t i = 0; i < principals.size(); ++i) {
153 /* If no hostname part, add it: */
154 if (principals[i].find('/') == std::string::npos) {
155 if (hostname.empty()) {
156 fprintf(stderr,
157 "Error: default hostname unspecified, "
158 "and service argument missing hostname.\n"
159 );
160 exit(1);
161 }
162 principals[i].append("/").append(hostname);
163 }
164 }
165 }
166
167
finalize_exec(msktutil_exec * exec,msktutil_flags * flags)168 int finalize_exec(msktutil_exec *exec, msktutil_flags *flags)
169 {
170 int ret;
171
172 char *temp_realm;
173 if (flags->realm_name.empty()) {
174 if (krb5_get_default_realm(g_context, &temp_realm)) {
175 fprintf(stderr, "Error: krb5_get_default_realm failed\n");
176 exit(1);
177 }
178 flags->realm_name = std::string(temp_realm);
179 #ifdef HEIMDAL
180 krb5_xfree(temp_realm);
181 #else
182 krb5_free_default_realm(g_context, temp_realm);
183 #endif
184 }
185
186 flags->lower_realm_name = flags->realm_name;
187 for(std::string::iterator it = flags->lower_realm_name.begin();
188 it != flags->lower_realm_name.end(); ++it) {
189 *it = std::tolower(*it);
190 }
191 if (exec->mode == MODE_CLEANUP) {
192 VERBOSE("cleanup mode: don't need AD server");
193 flags->server = "dummy";
194 } else {
195 if (flags->server.empty()) {
196 flags->server = get_dc_host(flags->realm_name,
197 flags->site,
198 flags->no_reverse_lookups);
199 if (flags->server.empty()) {
200 fprintf(stderr, "Error: get_dc_host failed\n");
201 exit(1);
202 }
203 }
204 }
205
206 get_default_keytab(flags);
207 signal(SIGINT, catch_int);
208 atexit(remove_files_at_exit);
209 create_fake_krb5_conf(flags);
210
211 if (exec->mode == MODE_CLEANUP) {
212 VERBOSE("cleanup mode: nothing more to do");
213 return (0);
214 }
215
216 if (exec->mode == MODE_PRECREATE && flags->hostname.empty()) {
217 /* Don't set a default hostname if none provided in pre-create
218 * mode. */
219 if (flags->sAMAccountName.empty()) {
220 fprintf(stderr,
221 "Error: You must supply either --computer-name "
222 "or --hostname when using pre-create mode.\n"
223 );
224 exit(1);
225 }
226 } else if (flags->hostname.empty()) {
227 /* Canonicalize the hostname if need be */
228 flags->hostname = get_default_hostname(flags->no_canonical_name);
229 } else {
230 flags->hostname = complete_hostname(flags->hostname);
231 }
232
233 /* Determine the sAMAccountName, if not set */
234 if (flags->sAMAccountName.empty()) {
235 if (flags->use_service_account) {
236 fprintf(stderr,
237 "Error: You must supply --account-name "
238 "when using --use-service-account.\n"
239 );
240 exit(1);
241 } else {
242 flags->sAMAccountName = get_default_samaccountname(flags) + "$";
243 }
244 }
245
246 /* Determine sAMAccountName_nodollar */
247 flags->sAMAccountName_nodollar = flags->sAMAccountName;
248 if (flags->sAMAccountName_nodollar[
249 flags->sAMAccountName_nodollar.size()-1] == '$') {
250 flags->sAMAccountName_nodollar.erase(
251 flags->sAMAccountName_nodollar.size()-1);
252 }
253
254 /* Add a "$" to machine accounts */
255 if ((!flags->use_service_account)
256 && (flags->sAMAccountName[flags->sAMAccountName.size()-1] != '$')) {
257 flags->sAMAccountName += "$";
258 }
259
260 /* Determine uppercase version of sAMAccountName */
261 flags->sAMAccountName_uppercase = flags->sAMAccountName;
262 for (std::string::size_type i=0;
263 i<flags->sAMAccountName_uppercase.length();
264 ++i) {
265 flags->sAMAccountName_uppercase[i]
266 = toupper(flags->sAMAccountName_uppercase[i]);
267 }
268
269 /* The sAMAccountName will cause win 9x, NT problems if longer
270 * than MAX_SAM_ACCOUNT_LEN characters */
271 if (flags->sAMAccountName.length() > MAX_SAM_ACCOUNT_LEN) {
272 fprintf(stderr,
273 "Error: The SAM name (%s) for this host is longer "
274 "than the maximum of MAX_SAM_ACCOUNT_LEN characters\n",
275 flags->sAMAccountName.c_str()
276 );
277 fprintf(stderr,
278 "Error: You can specify a shorter name using "
279 "--computer-name\n"
280 );
281 exit(1);
282 }
283 VERBOSE("SAM Account Name is: %s", flags->sAMAccountName.c_str());
284
285 /* Qualify entries in the principals list */
286 qualify_principal_vec(exec->add_principals, flags->hostname);
287 qualify_principal_vec(exec->remove_principals, flags->hostname);
288
289 /* Now, try to get kerberos credentials in order to connect to
290 * LDAP. */
291 flags->auth_type = find_working_creds(flags);
292 if (flags->auth_type == AUTH_NONE) {
293 fprintf(stderr,
294 "Error: could not find any credentials to authenticate with. "
295 "Neither keytab,\n"
296 "default machine password, nor calling user's tickets worked. "
297 "Try\n\"kinit\"ing yourself some tickets with permission to "
298 "create computer\nobjects, or pre-creating the computer "
299 "object in AD and selecting\n'reset account'.\n"
300 );
301 exit(1);
302 }
303
304 /* If we didn't get kerberos credentials because the old passord
305 * has expired we need to change it now */
306 if (flags->auth_type == AUTH_FROM_SUPPLIED_EXPIRED_PASSWORD) {
307 VERBOSE("Account password expired, changing it now...");
308 ret = set_password(flags);
309 if (ret) {
310 fprintf(stderr, "Error: failed to change password\n");
311 exit(1);
312 }
313 if (!get_creds(flags)) {
314 fprintf(stderr, "Error: failed to get kerberos credentials\n");
315 exit(1);
316 }
317 }
318
319 VERBOSE("Authenticated using method %d", flags->auth_type);
320
321 flags->ldap = new LDAPConnection(flags->server,
322 flags->no_reverse_lookups);
323
324 if (!flags->ldap->is_connected()) {
325 fprintf(stderr, "Error: ldap_connect failed\n");
326 /* Print a hint as to the likely cause: */
327 if (flags->auth_type == AUTH_FROM_USER_CREDS) {
328 fprintf(stderr, "--> Is your kerberos ticket expired? "
329 "You might try re-\"kinit\"ing.\n"
330 );
331 }
332 if (flags->no_reverse_lookups == false) {
333 fprintf(stderr, "--> Is DNS configured correctly? ");
334 fprintf(stderr, "You might try options \"--server\" "
335 "and \"--no-reverse-lookups\".\n"
336 );
337 }
338 exit(1);
339 }
340 ldap_get_base_dn(flags);
341 get_default_ou(flags);
342
343 return 0;
344 }
345
346
add_and_remove_principals(msktutil_exec * exec)347 int add_and_remove_principals(msktutil_exec *exec)
348 {
349 int ret = 0;
350
351 std::vector<std::string> &cur_princs(Globals::flags()->ad_principals);
352
353 for (size_t i = 0; i < exec->add_principals.size(); ++i) {
354 std::string principal = exec->add_principals[i];
355 if (std::find(cur_princs.begin(),
356 cur_princs.end(),
357 principal) == cur_princs.end()) {
358 /* Not already in the list, so add it. */
359 int loc_ret = ldap_add_principal(principal, Globals::flags());
360 if (loc_ret) {
361 fprintf(stderr, "Error: ldap_add_principal failed\n");
362 ret = 1;
363 continue;
364 }
365 }
366 }
367
368 for (size_t i = 0; i < exec->remove_principals.size(); ++i) {
369 std::string principal = exec->remove_principals[i];
370 if (std::find(cur_princs.begin(), cur_princs.end(), principal)
371 != cur_princs.end()) {
372 int loc_ret = ldap_remove_principal(principal, Globals::flags());
373 if (loc_ret) {
374 fprintf(stderr, "Error: ldap_remove_principal failed\n");
375 ret = 1;
376 continue;
377 }
378 } else {
379 fprintf(stderr,
380 "Error: principal %s cannot be removed, was not in "
381 "servicePrincipalName.\n",
382 principal.c_str()
383 );
384 for (size_t i = 0; i < cur_princs.size(); ++i)
385 fprintf(stderr, " %s\n", cur_princs[i].c_str());
386 ret = 1;
387 }
388 }
389 return ret;
390 }
391
392
do_help()393 void do_help()
394 {
395 fprintf(stdout, "Usage: %s [MODE] [OPTIONS]\n", PACKAGE_NAME);
396 fprintf(stdout, "\n");
397 fprintf(stdout, "Modes: \n");
398 fprintf(stdout, "\n");
399 fprintf(stdout, " create Creates a keytab for the current host or a given service account.\n");
400 fprintf(stdout, " (same as update -s host).\n");
401 fprintf(stdout, "\n");
402 fprintf(stdout, " update Updates the keytab for the current host or service account. This\n");
403 fprintf(stdout, " changes the account's password and updates the keytab with entries\n");
404 fprintf(stdout, " for all principals in servicePrincipalName and userPrincipalName.\n");
405 fprintf(stdout, " It also updates LDAP attributes for msDS-supportedEncryptionTypes,\n");
406 fprintf(stdout, " dNSHostName, and applies other options you specify.\n");
407 fprintf(stdout, "\n");
408 fprintf(stdout, " auto-update Same as update, but only if keytab fails to authenticate, or\n");
409 fprintf(stdout, " the last password change was more than 30 days ago\n");
410 fprintf(stdout, " (see --auto-update-interval). Useful to run from a daily cron job.\n");
411 fprintf(stdout, "\n");
412 fprintf(stdout, " pre-create Pre-create an account for the given host with default password\n");
413 fprintf(stdout, " but do not update local keytab.\n");
414 fprintf(stdout, " Requires -h or --computer-name argument.\n");
415 fprintf(stdout, " Implies --user-creds-only.\n");
416 fprintf(stdout, "\n");
417 fprintf(stdout, " flush Flushes all principals for the current host or service account\n");
418 fprintf(stdout, " from the keytab, and deletes servicePrincipalName from AD.\n");
419 fprintf(stdout, "\n");
420 fprintf(stdout, " delete Deletes the host or service account from Active Directory.\n");
421 fprintf(stdout, "\n");
422 fprintf(stdout, " cleanup Deletes entries from the keytab that are no longer needed.\n");
423 fprintf(stdout, "\n");
424 fprintf(stdout, "Common options: \n");
425 fprintf(stdout, " --help Displays this message\n");
426 fprintf(stdout, " -v, --version Display the current version\n");
427 fprintf(stdout, " --verbose Enable verbose messages.\n");
428 fprintf(stdout, " More then once to get LDAP debugging.\n");
429 fprintf(stdout, "\n");
430 fprintf(stdout, "Connection/setup options: \n");
431 fprintf(stdout, " -b, --base <base ou> Sets the LDAP base OU to use when creating an account.\n");
432 fprintf(stdout, " The default is read from AD (often CN=computers).\n");
433 fprintf(stdout, " --computer-name <name>, --account-name <name>\n");
434 fprintf(stdout, " Sets the computer account name or service account name\n");
435 fprintf(stdout, " to <name>.\n");
436 fprintf(stdout, " --old-account-password <password>\n");
437 fprintf(stdout, " Use supplied computer account password or service\n");
438 fprintf(stdout, " account password for authentication.\n");
439 fprintf(stdout, " This option is mutually exclusive with --user-creds-only.\n");
440 fprintf(stdout, " -h, --hostname <name> Use <name> as current hostname.\n");
441 fprintf(stdout, " --password <new_password>\n");
442 fprintf(stdout, " Specify the new account password instead of generating\n");
443 fprintf(stdout, " a random one. Consider the password policy settings when\n");
444 fprintf(stdout, " defining the string.\n");
445 fprintf(stdout, " --dont-change-password Do not create a new password. Try to use existing keys\n");
446 fprintf(stdout, " when performing keytab updates (update and create mode only).\n");
447 fprintf(stdout, " -k, --keytab <file> Use <file> for the keytab (both read and write).\n");
448 fprintf(stdout, " --keytab-auth-as <name>\n");
449 fprintf(stdout, " First try to authenticate to AD as principal <name>, using\n");
450 fprintf(stdout, " creds from the keytab, instead of using the account name\n");
451 fprintf(stdout, " principal or the host principal, etc.\n");
452 fprintf(stdout, " --server <address> Use a specific domain controller instead of looking\n");
453 fprintf(stdout, " up in DNS based upon realm.\n");
454 fprintf(stdout, " --server-behind-nat Ignore server IP validation error caused by NAT.\n");
455 fprintf(stdout, " --realm <realm> Use a specific kerberos realm instead of using\n");
456 fprintf(stdout, " default_realm from krb5.conf.\n");
457 fprintf(stdout, " --site <site> Find and use domain controller in specific AD site.\n");
458 fprintf(stdout, " This option is ignored if option --server is used.\n");
459 fprintf(stdout, " -N, --no-reverse-lookups\n");
460 fprintf(stdout, " Don't reverse-lookup the domain controller.\n");
461 fprintf(stdout, " -n, --no-canonical-name\n");
462 fprintf(stdout, " Do not attempt to canonicalize hostname while\n");
463 fprintf(stdout, " creating Kerberos principal(s).\n");
464 fprintf(stdout, " --user-creds-only Don't attempt to authenticate with machine keytab:\n");
465 fprintf(stdout, " only use user's credentials (from e.g. kinit).\n");
466 fprintf(stdout, " --auto-update-interval <days>\n");
467 fprintf(stdout, " Number of <days> when auto-update will change the\n");
468 fprintf(stdout, " account password. Defaults to 30 days.\n");
469 fprintf(stdout, "\n");
470 fprintf(stdout, "Object type/attribute-setting options:\n");
471 fprintf(stdout, " --use-service-account Create and maintain service account instead of\n");
472 fprintf(stdout, " machine account.\n");
473 fprintf(stdout, " --enable Enable the account.\n");
474 fprintf(stdout, " --delegation Set the account to be trusted for delegation.\n");
475 fprintf(stdout, " --disable-delegation Set the account to not be trusted for\n");
476 fprintf(stdout, " delegation.\n");
477 fprintf(stdout, " --description <text> Sets the description field on the account.\n");
478 fprintf(stdout, " --dont-expire-password Disables password expiration for the account.\n");
479 fprintf(stdout, " --dont-update-dnshostname\n");
480 fprintf(stdout, " Do not update dNSHostName attribute.\n");
481 fprintf(stdout, " --do-expire-password Undisables (puts back to default) password expiration.\n");
482 fprintf(stdout, " --enctypes <int> Sets msDs-supportedEncryptionTypes\n");
483 fprintf(stdout, " (OR of: 0x1=des-cbc-crc 0x2=des-cbc-md5\n");
484 fprintf(stdout, " 0x4=rc4-hmac-md5 0x8=aes128-cts-hmac-sha1\n");
485 fprintf(stdout, " 0x10=aes256-cts-hmac-sha1)\n");
486 fprintf(stdout, " Sets des-only in userAccountControl if set to 0x3.\n");
487 fprintf(stdout, " --allow-weak-crypto Enables the usage of DES keys for authentication\n");
488 fprintf(stdout, " --no-pac Sets the service principal to not include a PAC.\n");
489 fprintf(stdout, " --disable-no-pac Sets the service principal to include a PAC.\n");
490 fprintf(stdout, " -s, --service <name> Adds the service <name> for the current host or the\n");
491 fprintf(stdout, " given service account. The service is of the form\n");
492 fprintf(stdout, " <service>/<hostname>.\n");
493 fprintf(stdout, " If the hostname is omitted, assumes current hostname.\n");
494 fprintf(stdout, " --remove-service <name> Same, but removes instead of adds.\n");
495 fprintf(stdout, " --upn <principal> Set the user principal name to be <principal>.\n");
496 fprintf(stdout, " The realm name will be appended to this principal.\n");
497 fprintf(stdout, " --set-samba-secret Use the net changesecretpw command to locally set the\n");
498 fprintf(stdout, " machine account password in samba's secrets.tdb.\n");
499 fprintf(stdout, " $PATH need to include Samba's net command.\n");
500 fprintf(stdout, " --check-replication Wait until password change is reflected in LDAP.\n");
501 fprintf(stdout, "\n");
502 fprintf(stdout, "Cleanup options:\n");
503 fprintf(stdout, " --remove-old <number> Removes entries older than <number> days\n");
504 fprintf(stdout, " --remove-enctype <enctype>\n");
505 fprintf(stdout, " Removes entries with given <enctype>. Supported enctype\n");
506 fprintf(stdout, " strings are: des-cbc-crc,des-cbc-md5, arcfour, aes128\n");
507 fprintf(stdout, " and aes256\n");
508 }
509
510
do_version()511 void do_version()
512 {
513 fprintf(stdout, "%s version %s\n", PACKAGE_NAME, PACKAGE_VERSION);
514 }
515
516
wait_for_new_kvno(msktutil_flags * flags)517 static int wait_for_new_kvno(msktutil_flags *flags)
518 {
519 if (!flags->check_replication) {
520 return 0;
521 }
522
523 if (flags->auth_type == AUTH_FROM_SUPPLIED_EXPIRED_PASSWORD) {
524 VERBOSE("Warning: authenticated with expired password -- "
525 "no way to verify the password change in LDAP.");
526 return 0;
527 }
528
529 VERBOSE("Checking new kvno via ldap");
530
531 /* Loop and wait for the account and password set to replicate */
532 for (int this_time = 0; ; this_time += 5) {
533 krb5_kvno current_kvno = ldap_get_kvno(flags);
534 if (current_kvno == flags->kvno) {
535 return 0;
536 }
537
538 fprintf(stdout,
539 "Waiting for account replication (%d seconds past)\n",
540 this_time);
541 sleep(5);
542 }
543 }
544
545
execute(msktutil_exec * exec,msktutil_flags * flags)546 int execute(msktutil_exec *exec, msktutil_flags *flags)
547 {
548 int ret = 0;
549 if (flags->password_from_cmdline) {
550 VERBOSE("Using password from command line");
551 } else if (flags->dont_change_password) {
552 VERBOSE("Skipping creation of new password");
553 flags->password = flags->old_account_password;
554 } else if (exec->mode == MODE_CLEANUP) {
555 VERBOSE("cleanup mode: don't need a new password");
556 } else if (exec->mode == MODE_DELETE) {
557 VERBOSE("delete mode: don't need a new password");
558 } else {
559 /* Generate a random password and store it. */
560 ret = generate_new_password(flags);
561 if (ret) {
562 fprintf(stderr, "Error: generate_new_password failed\n");
563 return ret;
564 }
565 }
566 ret = finalize_exec(exec, flags);
567
568 if (ret) {
569 fprintf(stderr, "Error: finalize_exec failed\n");
570 exit(ret);
571 }
572 if (exec->mode == MODE_FLUSH) {
573 if (flags->use_service_account) {
574 fprintf(stdout,
575 "Flushing all entries for service account %s from the keytab %s\n",
576 flags->sAMAccountName.c_str(),
577 flags->keytab_writename.c_str());
578 } else {
579 fprintf(stdout,
580 "Flushing all entries for %s from the keytab %s\n",
581 flags->hostname.c_str(),
582 flags->keytab_writename.c_str());
583 }
584 ret = flush_keytab(flags);
585 return ret;
586 } else if (exec->mode == MODE_CREATE ||
587 exec->mode == MODE_UPDATE ||
588 exec->mode == MODE_AUTO_UPDATE) {
589 if (exec->mode == MODE_AUTO_UPDATE) {
590 if (flags->auth_type == AUTH_FROM_SAM_KEYTAB ||
591 flags->auth_type == AUTH_FROM_SAM_UPPERCASE_KEYTAB ||
592 flags->auth_type == AUTH_FROM_EXPLICIT_KEYTAB) {
593 std::string pwdLastSet = ldap_get_pwdLastSet(flags);
594 /* Windows timestamp is in
595 * 100-nanoseconds-since-1601. (or, tenths of
596 * microseconds) */
597 long long windows_timestamp = strtoll(pwdLastSet.c_str(),
598 NULL,
599 10);
600 long long epoch_bias_1601_to_1970 = 116444736000000000LL;
601 /* Unix timestamp is seconds since 1970. */
602 long long unix_timestamp;
603 if (windows_timestamp < epoch_bias_1601_to_1970) {
604 unix_timestamp = 0;
605 } else {
606 unix_timestamp = (windows_timestamp -
607 epoch_bias_1601_to_1970) / 10000000;
608 }
609 time_t current_unix_time = time(NULL);
610 long long days_since_password_change = (current_unix_time -
611 unix_timestamp) / 86400;
612 VERBOSE("Password last set %lld days ago.",
613 days_since_password_change);
614 if (days_since_password_change < flags->auto_update_interval) {
615 VERBOSE("Exiting because password was changed recently.");
616 return 0;
617 }
618 }
619 }
620
621 /* Check if computer account exists, update if so, create if
622 * not. */
623 if (! ldap_check_account(flags)) {
624 if (flags->password.empty()) {
625 fprintf(stderr,
626 "Error: a new AD account needs to be created "
627 "but there is no password.");
628 if (flags->dont_change_password) {
629 fprintf(stderr,
630 " Please provide a password with "
631 "--old-account-password <password>");
632 }
633 fprintf(stderr, "\n");
634 exit(1);
635 } else {
636 ldap_create_account(flags);
637 flags->kvno = ldap_get_kvno(flags);
638 }
639
640 } else {
641 /* We retrieve the kvno _before_ the password change and
642 * increment it. */
643 flags->kvno = ldap_get_kvno(flags);
644 if ((flags->auth_type != AUTH_FROM_SUPPLIED_EXPIRED_PASSWORD) &&
645 (!flags->dont_change_password)) {
646 flags->kvno++;
647 }
648
649 if ((flags->auth_type != AUTH_FROM_SUPPLIED_EXPIRED_PASSWORD) &&
650 (!flags->dont_change_password)) {
651 /* Set the password. */
652 ret = set_password(flags);
653 if (ret) {
654 fprintf(stderr, "Error: set_password failed\n");
655 if (flags->use_service_account) {
656 fprintf(stderr,
657 "Hint: Does your password policy allow to "
658 "change %s's password?\n",
659 flags->sAMAccountName.c_str()
660 );
661 fprintf(stderr, " For example, there could be a "
662 "\"Minimum password age\" policy preventing\n"
663 );
664 fprintf(stderr, " passwords from being changed "
665 "too frequently. If so, you can reset the\n"
666 );
667 fprintf(stderr, " password instead of changing "
668 "it using the --user-creds-only option.\n"
669 );
670 fprintf(stderr, " Be aware that you need a "
671 "ticket of a user with administrative "
672 "privileges\n"
673 );
674 fprintf(stderr, " for that.\n");
675 }
676 return ret;
677 }
678 }
679 }
680
681 /* Add and remove principals to servicePrincipalName in LDAP.*/
682 add_and_remove_principals(exec);
683
684 remove_keytab_entries(flags, exec->remove_principals);
685
686 /* update keytab */
687 if (flags->use_service_account) {
688 VERBOSE("Updating all entries for service account %s in the keytab %s",
689 flags->sAMAccountName.c_str(),
690 flags->keytab_writename.c_str());
691 } else {
692 VERBOSE("Updating all entries for computer account %s in the keytab %s",
693 flags->sAMAccountName.c_str(),
694 flags->keytab_writename.c_str());
695 }
696 update_keytab(flags);
697
698 add_keytab_entries(flags);
699
700 wait_for_new_kvno(flags);
701 return ret;
702 } else if (exec->mode == MODE_PRECREATE) {
703 /* Change account password to default value: */
704 flags->password = create_default_machine_password(
705 flags->sAMAccountName);
706 /* Check if computer account exists, update if so, create if
707 * not. */
708 if (! ldap_check_account(flags)) {
709 ldap_create_account(flags);
710 }
711
712 /* Set the password. */
713 ret = set_password(flags);
714 if (ret) {
715 fprintf(stderr, "Error: set_password failed\n");
716 return ret;
717 }
718
719 /* And add and remove principals to servicePrincipalName in
720 * LDAP. */
721 add_and_remove_principals(exec);
722 wait_for_new_kvno(flags);
723 return ret;
724 } else if (exec->mode == MODE_CLEANUP) {
725 fprintf(stdout, "Cleaning keytab %s\n",
726 flags->keytab_writename.c_str());
727 cleanup_keytab(flags);
728 return 0;
729 }
730
731 return 0;
732 }
733
734
set_mode(msktutil_mode mode)735 void msktutil_exec::set_mode(msktutil_mode mode) {
736 if (this->mode != MODE_NONE) {
737 fprintf(stderr, "Error: only one mode argument may be provided.\n");
738 fprintf(stderr, "\nFor help, try running %s --help\n\n", PACKAGE_NAME);
739 exit(1);
740 }
741 this->mode = mode;
742 }
743
744 Globals *Globals::instance;
745
main(int argc,char * argv[])746 int main(int argc, char *argv [])
747 {
748 /* unbuffer stdout. */
749 setbuf(stdout, NULL);
750 initialize_g_context();
751
752 int i;
753 int start_i;
754 start_i = 2;
755 msktutil_exec *exec = Globals::exec();
756 msktutil_flags *flags = Globals::flags();
757
758 if (argc > 1) {
759 /* determine MODE */
760 if (!strcmp(argv[1], "create")) {
761 exec->set_mode(MODE_CREATE);
762 } else if (!strcmp(argv[1], "update")) {
763 exec->set_mode(MODE_UPDATE);
764 } else if (!strcmp(argv[1], "auto-update")) {
765 exec->set_mode(MODE_AUTO_UPDATE);
766 } else if (!strcmp(argv[1], "pre-create")) {
767 exec->set_mode(MODE_PRECREATE);
768 } else if (!strcmp(argv[1], "flush")) {
769 exec->set_mode(MODE_FLUSH);
770 } else if (!strcmp(argv[1], "cleanup")) {
771 exec->set_mode(MODE_CLEANUP);
772 } else if (!strcmp(argv[1], "delete")) {
773 exec->set_mode(MODE_DELETE);
774 }
775 }
776
777 if (exec->mode == MODE_NONE) {
778 /* compatibility for old command line syntax (e.g. "--create"
779 * or "-c" instead of "create") */
780 start_i = 1;
781 }
782
783 for (i = start_i; i < argc; i++) {
784
785 /* Display Version Message and exit */
786 if (!strcmp(argv[i], "-v") || !strcmp(argv[i], "--version")) {
787 do_version();
788 return 0;
789 }
790
791 /* Display Help Messages and exit */
792 if (!strcmp(argv[i], "--help") || !strcmp(argv[i], "--usage")) {
793 do_help();
794 return 0;
795 }
796
797 /* Flush the keytab */
798 if (!strcmp(argv[i], "--flush") || !strcmp(argv[i], "-f")) {
799 exec->set_mode(MODE_FLUSH);
800 continue;
801 }
802
803 /* Update All Principals */
804 if (!strcmp(argv[i], "--update") || !strcmp(argv[i], "-u")) {
805 exec->set_mode(MODE_UPDATE);
806 continue;
807 }
808
809 /* Update All Principals, if needed */
810 if (!strcmp(argv[i], "--auto-update")) {
811 exec->set_mode(MODE_AUTO_UPDATE);
812 continue;
813 }
814
815 /* Create 'Default' Keytab */
816 if (!strcmp(argv[i], "--create") || !strcmp(argv[i], "-c")) {
817 exec->set_mode(MODE_CREATE);
818 continue;
819 }
820
821 /* Pre-create computer account for another host */
822 if (!strcmp(argv[i], "--precreate")) {
823 exec->set_mode(MODE_PRECREATE);
824 flags->user_creds_only = true;
825 continue;
826 }
827
828 /* Service Principal Name */
829 if (!strcmp(argv[i], "--service") || !strcmp(argv[i], "-s")) {
830 if (++i < argc) {
831 exec->add_principals.push_back(argv[i]);
832 } else {
833 fprintf(stderr,
834 "Error: No service principal given after '%s'\n",
835 argv[i - 1]
836 );
837 goto error;
838 }
839 continue;
840 }
841 if (!strcmp(argv[i], "--remove-service")) {
842 if (++i < argc) {
843 exec->remove_principals.push_back(argv[i]);
844 } else {
845 fprintf(stderr,
846 "Error: No service principal given after '%s'\n",
847 argv[i - 1]
848 );
849 goto error;
850 }
851 continue;
852 }
853
854 /* Host name */
855 if (!strcmp(argv[i], "--host") ||
856 !strcmp(argv[i], "--hostname") ||
857 !strcmp(argv[i], "-h")) {
858 if (++i < argc) {
859 flags->hostname = argv[i];
860 } else {
861 fprintf(stderr,
862 "Error: No name given after '%s'\n",
863 argv[i - 1]
864 );
865 goto error;
866 }
867 continue;
868 }
869
870 /* no canonical name */
871 if (!strcmp(argv[i], "--no-canonical-name") ||
872 !strcmp(argv[i], "-n")) {
873 flags->no_canonical_name = true;
874 continue;
875 }
876
877 /* computer password */
878 if (!strcmp(argv[i], "--old-account-password")) {
879 if (++i < argc) {
880 flags->old_account_password = argv[i];
881 } else {
882 fprintf(stderr,
883 "Error: No password given after '%s'\n",
884 argv[i - 1]
885 );
886 goto error;
887 }
888 continue;
889 }
890
891 if (!strcmp(argv[i], "--password")) {
892 if (++i < argc) {
893 flags->password_from_cmdline = true;
894 flags->password = argv[i];
895 } else {
896 fprintf(stderr,
897 "Error: No password given after '%s'\n",
898 argv[i - 1]
899 );
900 goto error;
901 }
902 continue;
903 }
904
905 /* do not change the password */
906 if (!strcmp(argv[i], "--dont-change-password")) {
907 flags->dont_change_password = true;
908 continue;
909 }
910
911 /* site */
912 if (!strcmp(argv[i], "--site")) {
913 if (++i < argc) {
914 flags->site = argv[i];
915 } else {
916 fprintf(stderr,
917 "Error: No site given after '%s'\n",
918 argv[i - 1]
919 );
920 goto error;
921 }
922 continue;
923 }
924
925 /* W2008 msDs-supportedEncryptionTypes */
926 if (!strcmp(argv[i], "--enctypes")) {
927 if (++i < argc) {
928 set_supportedEncryptionTypes(flags, argv[i]);
929 } else {
930 fprintf(stderr,
931 "Error: No enctype after '%s'\n",
932 argv[i - 1]
933 );
934 goto error;
935 }
936 continue;
937 }
938
939 /* Re-activate DES encryption in fake krb5.conf */
940 if (!strcmp(argv[i], "--allow-weak-crypto")) {
941 flags->allow_weak_crypto = true;
942 continue;
943 }
944
945 /* Enable the account */
946 if (!strcmp(argv[i], "--enable")) {
947 flags->disable_account = VALUE_OFF;
948 continue;
949 }
950
951 /* Disable the PAC ? */
952 if (!strcmp(argv[i], "--no-pac")) {
953 flags->no_pac = VALUE_ON;
954 continue;
955 }
956 if (!strcmp(argv[i], "--disable-no-pac")) {
957 flags->no_pac = VALUE_OFF;
958 continue;
959 }
960
961 /* Use service account */
962 if (!strcmp(argv[i], "--use-service-account")) {
963 flags->use_service_account = true;
964 continue;
965 }
966
967 /* Trust for delegation ? */
968 if (!strcmp(argv[i], "--delegation")) {
969 flags->delegate = VALUE_ON;
970 continue;
971 }
972 if (!strcmp(argv[i], "--disable-delegation")) {
973 flags->delegate = VALUE_OFF;
974 continue;
975 }
976
977 /* Password expiry (is rotation required?) */
978 if (!strcmp(argv[i], "--dont-expire-password")) {
979 flags->dont_expire_password = VALUE_ON;
980 continue;
981 }
982
983 /* Prevent dnsHostName attribute update */
984 if (!strcmp(argv[i], "--dont-update-dnshostname")) {
985 flags->dont_update_dnshostname = VALUE_ON;
986 continue;
987 }
988
989 if (!strcmp(argv[i], "--do-expire-password")) {
990 flags->dont_expire_password = VALUE_OFF;
991 continue;
992 }
993
994 /* Use a certain sam account name */
995 if (!strcmp(argv[i], "--computer-name") ||
996 !strcmp(argv[i], "--account-name")) {
997 if (++i < argc) {
998 flags->sAMAccountName = argv[i];
999 } else {
1000 fprintf(stderr,
1001 "Error: No name given after '%s'\n",
1002 argv[i - 1]
1003 );
1004 goto error;
1005 }
1006 continue;
1007 }
1008
1009 if (!strcmp(argv[i], "--upn")) {
1010 if (++i < argc) {
1011 flags->set_userPrincipalName = true;
1012 flags->userPrincipalName = argv[i];
1013 } else {
1014 fprintf(stderr,
1015 "Error: No principal given after '%s'\n",
1016 argv[i - 1]
1017 );
1018 goto error;
1019 }
1020 continue;
1021 }
1022
1023 /* Use certain keytab file */
1024 if (!strcmp(argv[i], "--keytab") || !strcmp(argv[i], "-k")) {
1025 if (++i < argc) {
1026 flags->keytab_file = argv[i];
1027 } else {
1028 fprintf(stderr,
1029 "Error: No file given after '%s'\n",
1030 argv[i - 1]
1031 );
1032 goto error;
1033 }
1034 continue;
1035 }
1036
1037 /* Use a certain LDAP base OU ? */
1038 if (!strcmp(argv[i], "--base") || !strcmp(argv[i], "-b")) {
1039 if (++i < argc) {
1040 flags->ldap_ou = argv[i];
1041 } else {
1042 fprintf(stderr,
1043 "Error: No base given after '%s'\n",
1044 argv[i - 1]
1045 );
1046 goto error;
1047 }
1048 continue;
1049 }
1050
1051 /* Set the description on the computer account */
1052 if (!strcmp(argv[i], "--description")) {
1053 if (++i < argc) {
1054 flags->description = argv[i];
1055 } else {
1056 fprintf(stderr,
1057 "Error: No description given after '%s'\n",
1058 argv[i - 1]
1059 );
1060 goto error;
1061 }
1062 continue;
1063 }
1064
1065 /* Use a certain LDAP server */
1066 if (!strcmp(argv[i], "--server")) {
1067 if (++i < argc) {
1068 flags->server = argv[i];
1069 } else {
1070 fprintf(stderr,
1071 "Error: No server given after '%s'\n",
1072 argv[i - 1]
1073 );
1074 goto error;
1075 }
1076 continue;
1077 }
1078
1079 /* ignore server IP validation error caused by NAT */
1080 if (!strcmp(argv[i], "--server-behind-nat")) {
1081 flags->server_behind_nat = true;
1082 continue;
1083 }
1084
1085 /* Use a certain realm */
1086 if (!strcmp(argv[i], "--realm")) {
1087 if (++i < argc) {
1088 flags->realm_name = argv[i];
1089 } else {
1090 fprintf(stderr,
1091 "Error: No realm given after '%s'\n",
1092 argv[i - 1]
1093 );
1094 goto error;
1095 }
1096 continue;
1097 }
1098
1099 /* do not reverse lookup server names */
1100 if (!strcmp(argv[i], "--no-reverse-lookups") ||
1101 !strcmp(argv[i], "-N")) {
1102 flags->no_reverse_lookups = true;
1103 continue;
1104 }
1105
1106 /* synchronize machine password with samba */
1107 if (!strcmp(argv[i], "--set-samba-secret")) {
1108 flags->set_samba_secret = true;
1109 continue;
1110 }
1111
1112 /* Use user kerberos credentials only */
1113 if (!strcmp(argv[i], "--user-creds-only")) {
1114 flags->user_creds_only = true;
1115 continue;
1116 }
1117
1118 if (!strcmp(argv[i], "--keytab-auth-as")) {
1119 if (++i < argc) {
1120 flags->keytab_auth_princ = argv[i];
1121 } else {
1122 fprintf(stderr,
1123 "Error: No principal given after '%s'\n",
1124 argv[i - 1]
1125 );
1126 goto error;
1127 }
1128 continue;
1129 }
1130
1131 if (!strcmp(argv[i], "--auto-update-interval")) {
1132 if (++i < argc) {
1133 flags->auto_update_interval = atoi(argv[i]);
1134 } else {
1135 fprintf(stderr,
1136 "Error: No number given after '%s'\n",
1137 argv[i - 1]
1138 );
1139 goto error;
1140 }
1141 continue;
1142 }
1143
1144 if (!strcmp(argv[i], "--remove-old")) {
1145 if (++i < argc) {
1146 flags->cleanup_days = atoi(argv[i]);
1147 } else {
1148 fprintf(stderr,
1149 "Error: No number given after '%s'\n",
1150 argv[i - 1]
1151 );
1152 goto error;
1153 }
1154 continue;
1155 }
1156
1157 if (!strcmp(argv[i], "--remove-enctype")) {
1158 if (++i < argc) {
1159 set_cleanup_enctype(flags, argv[i]);
1160 } else {
1161 fprintf(stderr,
1162 "Error: No number given after '%s'\n",
1163 argv[i - 1]
1164 );
1165 goto error;
1166 }
1167 continue;
1168 }
1169
1170 /* wait for LDAP replication */
1171 if (!strcmp(argv[i], "--check-replication")) {
1172 flags->check_replication = true;
1173 continue;
1174 }
1175
1176 /* Display Verbose Messages */
1177 if (!strcmp(argv[i], "--verbose")) {
1178 do_verbose();
1179 continue;
1180 }
1181
1182 /* Unrecognized */
1183 fprintf(stderr, "Error: Unknown parameter (%s)\n", argv[i]);
1184 goto error;
1185 }
1186
1187 /* make --old-account-password and --user-creds-only mutually
1188 * exclusive: */
1189 if (strlen(flags->old_account_password.c_str()) &&
1190 flags->user_creds_only) {
1191 fprintf(stderr,
1192 "Error: --old-account-password and --user-creds-only "
1193 "are mutually exclusive\n");
1194 goto error;
1195 }
1196
1197 /* allow --dont-change-password only in update mode or when create
1198 * mode is called with --old-account-password */
1199 if (flags->dont_change_password &&
1200 !(exec->mode == MODE_UPDATE || exec->mode == MODE_CREATE)
1201 ) {
1202 fprintf(stderr,
1203 "Error: --dont-change-password can only be used in update or create mode\n"
1204 );
1205 goto error;
1206 }
1207
1208 if (flags->dont_change_password && exec->mode == MODE_CREATE && flags->old_account_password.empty()) {
1209 fprintf(stderr,
1210 "Error: --dont-change-password needs --old-account-password <password> in create mode\n"
1211 );
1212 goto error;
1213 }
1214
1215 /* allow --remove-enctype only in cleanup mode */
1216 if (exec->mode != MODE_CLEANUP &&
1217 flags->cleanup_enctype != VALUE_IGNORE) {
1218 fprintf(stderr,
1219 "Error: --remove-enctype can only be used in cleanup mode\n"
1220 );
1221 goto error;
1222 }
1223
1224 /* allow --remove-old only in cleanup mode */
1225 if (exec->mode != MODE_CLEANUP && flags->cleanup_days != -1) {
1226 fprintf(stderr,
1227 "Error: --remove-old can only be used in cleanup mode\n"
1228 );
1229 goto error;
1230 }
1231
1232 if (flags->enctypes == VALUE_ON) {
1233 unsigned known= MS_KERB_ENCTYPE_DES_CBC_CRC |
1234 MS_KERB_ENCTYPE_DES_CBC_MD5 |
1235 MS_KERB_ENCTYPE_RC4_HMAC_MD5 |
1236 MS_KERB_ENCTYPE_AES128_CTC_HMAC_SHA1_96 |
1237 MS_KERB_ENCTYPE_AES256_CTS_HMAC_SHA1_96;
1238
1239 if ((flags->supportedEncryptionTypes|known) != known) {
1240 fprintf(stderr,
1241 "Error: Unsupported --enctypes must be integer that "
1242 "fits mask=0x%x\n",
1243 known
1244 );
1245 goto error;
1246 }
1247 if (flags->supportedEncryptionTypes == 0) {
1248 fprintf(stderr, "Error: --enctypes must not be zero\n");
1249 goto error;
1250 }
1251 }
1252
1253 if (exec->mode == MODE_CREATE && !flags->use_service_account) {
1254 exec->add_principals.push_back("host");
1255 }
1256
1257 if (exec->mode == MODE_NONE && !exec->add_principals.empty()) {
1258 exec->set_mode(MODE_UPDATE);
1259 }
1260
1261 if (exec->mode == MODE_CLEANUP &&
1262 flags->cleanup_days == -1 &&
1263 flags->cleanup_enctype == VALUE_IGNORE) {
1264 fprintf(stderr,
1265 "Error: cleanup mode needs --remove-old or "
1266 "--remove-enctype\n"
1267 );
1268 goto error;
1269 }
1270
1271 if (exec->mode == MODE_NONE) {
1272 /* Default, no options present */
1273 fprintf(stderr, "Error: No command given\n");
1274 goto error;
1275 }
1276
1277 try {
1278 return execute(exec, flags);
1279 } catch (Exception &e) {
1280 fprintf(stderr, "%s\n", e.what());
1281 exit(1);
1282 }
1283
1284 error:
1285 fprintf(stderr, "\nFor help, try running %s --help\n\n", PACKAGE_NAME);
1286 return 1;
1287 }
1288
1289 Globals*
get()1290 Globals::get() {
1291 if (instance==NULL) {
1292 instance = new Globals();
1293 instance->_flags = new msktutil_flags;
1294 instance->_exec = new msktutil_exec;
1295 }
1296 return instance;
1297 }
1298
1299 void
set_supportedEncryptionTypes(char * value)1300 Globals::set_supportedEncryptionTypes(char * value)
1301 {
1302 _flags->enctypes = VALUE_ON;
1303 _flags->supportedEncryptionTypes = strtol(value, NULL, 0);
1304 }
1305
1306
msktutil_flags()1307 msktutil_flags::msktutil_flags() :
1308 password(),
1309 password_from_cmdline(false),
1310 ldap(NULL),
1311 set_userPrincipalName(false),
1312 no_reverse_lookups(false),
1313 no_canonical_name(false),
1314 server_behind_nat(false),
1315 set_samba_secret(false),
1316 check_replication(false),
1317 dont_change_password(false),
1318 dont_expire_password(VALUE_IGNORE),
1319 dont_update_dnshostname(VALUE_OFF),
1320 disable_account(VALUE_IGNORE),
1321 no_pac(VALUE_IGNORE),
1322 delegate(VALUE_IGNORE),
1323 ad_userAccountControl(0),
1324 ad_enctypes(VALUE_IGNORE),
1325 ad_supportedEncryptionTypes(0),
1326 enctypes(VALUE_IGNORE),
1327 /* default values we *want* to support */
1328 supportedEncryptionTypes(MS_KERB_ENCTYPE_RC4_HMAC_MD5 |
1329 MS_KERB_ENCTYPE_AES128_CTC_HMAC_SHA1_96 |
1330 MS_KERB_ENCTYPE_AES256_CTS_HMAC_SHA1_96),
1331 auth_type(0),
1332 user_creds_only(false),
1333 use_service_account(false),
1334 allow_weak_crypto(false),
1335 password_expired(false),
1336 auto_update_interval(30),
1337 kvno(0),
1338 cleanup_days(-1),
1339 cleanup_enctype(VALUE_IGNORE)
1340 {
1341 /* Check for environment variables as well. These variables will
1342 * be overriden by command line arguments. */
1343 if (getenv("MSKTUTIL_KEYTAB")) {
1344 keytab_file = getenv("MSKTUTIL_KEYTAB");
1345 }
1346 if (getenv("MSKTUTIL_NO_PAC")) {
1347 no_pac = VALUE_ON;
1348 }
1349 if (getenv("MSKTUTIL_DELEGATION")) {
1350 delegate = VALUE_ON;
1351 }
1352 if (getenv("MSKTUTIL_LDAP_BASE")) {
1353 ldap_ou = getenv("MSKTUTIL_LDAP_BASE");
1354 }
1355 if (getenv("MSKTUTIL_SERVER")) {
1356 server = getenv("MSKTUTIL_SERVER");
1357 }
1358 }
1359
1360
~msktutil_flags()1361 msktutil_flags::~msktutil_flags()
1362 {
1363 ldap_cleanup(this);
1364 init_password(this);
1365 }
1366
1367
msktutil_exec()1368 msktutil_exec::msktutil_exec() :
1369 mode(MODE_NONE)
1370 {
1371 }
1372
1373
~msktutil_exec()1374 msktutil_exec::~msktutil_exec()
1375 {
1376 VERBOSE("Destroying msktutil_exec");
1377 remove_fake_krb5_conf();
1378 remove_ccache();
1379 }
1380