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