1   /*
   2    * Copyright 2004 Sun Microsystems, Inc.  All rights reserved.
   3    * Use is subject to license terms.
   4    */
   5   
   6 | #pragma ident        "@(#)kadmin.c        1.13        04/09/08 SMI"
   6 | #pragma ident        "@(#)kadmin.c        1.12        04/08/19 SMI"
   7   
   8   /*
   9    * Copyright 1994 by the Massachusetts Institute of Technology.
  10    * All Rights Reserved.
  11    *
  12    * Export of this software from the United States of America may
  13    *   require a specific license from the United States Government.
  14    *   It is the responsibility of any person or organization contemplating
  15    *   export to obtain such a license before exporting.
  16    * 
  17    * WITHIN THAT CONSTRAINT, permission to use, copy, modify, and
  18    * distribute this software and its documentation for any purpose and
  19    * without fee is hereby granted, provided that the above copyright
  20    * notice appear in all copies and that both that copyright notice and
  21    * this permission notice appear in supporting documentation, and that
  22    * the name of M.I.T. not be used in advertising or publicity pertaining
  23    * to distribution of the software without specific, written prior
  24    * permission.  Furthermore if you modify this software you must label
  25    * your software as modified software and not distribute it in such a
  26    * fashion that it might be confused with the original M.I.T. software.
  27    * M.I.T. makes no representations about the suitability of
  28    * this software for any purpose.  It is provided "as is" without express
  29    * or implied warranty.
  30    * 
  31    * kadmin.c: base functions for a kadmin command line interface using
  32    * the OVSecure library
  33    */
  34   
  35   #include <krb5.h>
  36   #include <k5-int.h>
  37   #include <kadm5/admin.h>
  38   #include <stdio.h>
  39   #include <string.h>
  40   #include <sys/types.h>
  41   #include <math.h>
  42   #include <unistd.h>
  43   #include <pwd.h>
  44   /* #include <sys/timeb.h> */
  45   #include <time.h>
  46   #include <libintl.h>
  47   
  48   /*
  49    * Solaris:  the following are needed for paging
  50    */
  51   #include <signal.h>
  52   #include <sys/wait.h>
  53   
  54   /* command name when called "locally" (i.e. non-networked client ) */
  55   #define KADMIN_LOCAL_NAME "kadmin.local"
  56   
  57   /* functions defined in remote/local specific files */
  58   extern void usage(const char *);
  59   extern void debugEnable(int);
  60   
  61   /* local principal helpers */
  62   static char *find_component(const char *, char);
  63   static char *trim_principal(char *);
  64   static char *build_admin_princ(const char *, const char *);
  65   
  66   /*
  67    * special struct to convert flag names for principals
  68    * to actual krb5_flags for a principal
  69    */
  70   struct pflag {
  71       char *flagname;                /* name of flag as typed to CLI */
  72       int flaglen;                /* length of string (not counting -,+) */
  73       krb5_flags theflag;                /* actual principal flag to set/clear */
  74       int set;                        /* 0 means clear, 1 means set (on '-') */
  75   };

 ----Unchanged portion omitted----

 195   
 196   char *
 197   kadmin_startup(argc, argv)
 198       int argc;
 199       char *argv[];
 200   {
 201       extern krb5_kt_ops krb5_ktf_writable_ops;
 202       extern char *optarg;
 203       char *princstr = NULL, *keytab_name = NULL, *query = NULL;
 204       char *password = NULL;
 205           char *kadmin_princ = NULL;
 206       char *luser, *canon, *cp;
 207           int optchar, use_keytab = 0, debug = 0;
 208       struct passwd *pw;
 209       kadm5_ret_t retval;
 210       krb5_ccache cc;
 211       krb5_principal princ;
 212       kadm5_config_params params;
 213   
 214       memset((char *) &params, 0, sizeof(params));
 215       
 216       if (retval = krb5_init_context(&context)) {
 217           com_err(whoami, retval,
 218                   gettext("while initializing krb5 library"));
 219            exit(1);
 220       }
 221       while ((optchar = getopt(argc, argv, "Dr:p:kq:w:d:s:mc:t:e:O")) != EOF) {
 222           switch (optchar) {
 223           case 'O':        /* Undocumented option for testing only */
 224                   kadmin_princ = KADM5_ADMIN_SERVICE_P;
 225                   break;
 226           case 'D':
 227                   debug++;
 228                   break;
 229           case 'r':
 230               def_realm = optarg;
 231               break;
 232           case 'p':
 233                   princstr = strdup(optarg);
 234                   if (princstr == NULL) {
 235                           fprintf(stderr, gettext("Out of memory in %s\n"),
 236                                   whoami);
 237                           exit(1);
 238                   }
 239                   break;
 240           case 'c':
 241               ccache_name = optarg;
 242               break;
 243           case 'k':
 244               use_keytab++;
 245               break;
 246          case 't':
 247               keytab_name = optarg;
 248               break;
 249           case 'w':
 250               password = optarg;
 251               break;
 252           case 'q':
 253               query = optarg;
 254               break;
 255           case 'd':
 256               params.dbname = optarg;
 257               params.mask |= KADM5_CONFIG_DBNAME;
 258               break;
 259           case 's':
 260               params.admin_server = optarg;
 261               params.mask |= KADM5_CONFIG_ADMIN_SERVER;
 262               break;
 263           case 'm':
 264               params.mkey_from_kbd = 1;
 265               params.mask |= KADM5_CONFIG_MKEY_FROM_KBD;
 266               break;
 267           case 'e':
 268               retval = krb5_string_to_keysalts(optarg,
 269                                        ", \t", ":.-", 0,
 270                                        &params.keysalts,
 271                                        &params.num_keysalts);
 272               if (retval) {
 273                   com_err(whoami, retval,
 274                           gettext("while parsing keysalts %s"), optarg);
 275                   exit(1);
 276               }
 277               params.mask |= KADM5_CONFIG_ENCTYPES;
 278               break;
 279           default:
 280               usage(whoami);
 281           }
 282       }
 283   
 284       debugEnable(debug);
 285   
 286       if ((ccache_name && use_keytab) ||
 287           (keytab_name && !use_keytab))
 288           usage(whoami);
 289   
 290       if (def_realm == NULL && krb5_get_default_realm(context, &def_realm)) {
 291           free(princstr);
 292           fprintf(stderr,
 293                   gettext("%s: unable to get default realm\n"), whoami);
 294           exit(1);
 295       }
 296       params.mask |= KADM5_CONFIG_REALM;
 297       params.realm = def_realm;
 298   
 299       if (kadmin_princ == NULL) {
 300           if (kadm5_get_adm_host_srv_name(context,
 301                                  def_realm, &kadmin_princ)) {
 302                   fprintf(stderr,
 303                           gettext("%s: unable to get host based "
 304                                   "service name for realm %s\n"),
 305                           whoami, def_realm);
 306                   free(princstr);
 307                   exit(1);
 308           }
 309       }
 310   
 311       /*
 312        * Set cc to an open credentials cache, either specified by the -c
 313        * argument or the default.
 314        */
 315       if (ccache_name == NULL) {
 316            if (retval = krb5_cc_default(context, &cc)) {
 317                 com_err(whoami, retval,
 318                                   gettext("while opening default "
 319                                           "credentials cache"));
 320                 exit(1);
 321            }
 322       } else {
 323            if (retval = krb5_cc_resolve(context, ccache_name, &cc)) {
 324                 com_err(whoami, retval,
 325                           gettext("while opening credentials cache %s"),
 326                           ccache_name);
 327                 exit(1);
 328            }
 329       }
 330   
 331       /*
 332        * If no principal name is specified: If a ccache was specified and
 333        * its primary principal name can be read, it is used, else if a
 334        * keytab was specified, the principal name is host/hostname,
 335        * otherwise append "/admin" to the primary name of the default
 336        * ccache, $USER, or pw_name.
 337        *
 338        * Gee, 100+ lines to figure out the client principal name.  This
 339        * should be compressed...
 340        */
 341               
 342       if (princstr == NULL) {
 343           if (ccache_name != NULL &&
 344               !krb5_cc_get_principal(context, cc, &princ)) {
 345                   if (retval = krb5_unparse_name(context, princ,
 346                                       &princstr)) {
 347                     com_err(whoami, retval,
 348                           gettext("while canonicalizing principal name"));
 349                           krb5_free_principal(context, princ);
 350                     exit(1);
 351                   }
 352                   krb5_free_principal(context, princ);
 353        } else if (use_keytab != 0) {
 354               if (retval = krb5_sname_to_principal(context, NULL,
 355                                             "host", KRB5_NT_SRV_HST,
 356                                             &princ)) {
 357                   com_err(whoami, retval,
 358                           gettext("creating host service principal"));
 359                   exit(1);
 360               }
 361               if (retval = krb5_unparse_name(context, princ,
 362                                               &princstr)) {
 363                     com_err(whoami, retval,
 364                           gettext("while canonicalizing "
 365                                   "principal name"));
 366                     krb5_free_principal(context, princ);
 367                     exit(1);
 368                }
 369                krb5_free_principal(context, princ);
 370           } else if (!krb5_cc_get_principal(context, cc, &princ)) {
 371               char *realm = NULL;
 372   
 373               if (krb5_unparse_name(context, princ, &canon)) {
 374                   fprintf(stderr,
 375                           gettext("%s: unable to canonicalize "
 376                                   "principal\n"), whoami);
 377                   krb5_free_principal(context, princ);
 378                   exit(1);
 379               }
 380               krb5_free_principal(context, princ);
 381                           (void) trim_principal(canon);
 382                           princstr = build_admin_princ(canon, def_realm);
 383               free(canon);
 384           } else if (luser = getenv("USER")) {
 385                   princstr = build_admin_princ(luser, def_realm);
 386           } else if (pw = getpwuid(getuid())) {
 387                   princstr = build_admin_princ(pw->pw_name, def_realm);
 388           } else {
 389                   fprintf(stderr,
 390                           gettext("%s: unable to figure out "
 391                                   "a principal name\n"),
 392                                   whoami);
 393                   exit(1);
 394           }
 395       } else { /* (princstr != NULL) */
 396           /* See if we need to add the default realm */
 397           if (find_component(princstr, '@') == NULL) {
 398                   size_t len;
 399   
 400                   /*         principal     @        realm       NULL */
 401                   len = strlen(princstr) + 1 + strlen(def_realm) + 1;
 402                   princstr = realloc(princstr, len);
 403                   if (princstr == NULL) {
 404                           fprintf(stderr,
 405                                   gettext("%s: out of memory\n"), whoami);
 406                           exit(1);
 407                       }
 408                   strcat(princstr, "@");
 409                   strcat(princstr, def_realm);
 410           }
 411       }
 412   
 413       /*
 414        * Initialize the kadm5 connection.  If we were given a ccache, use
 415        * it.  Otherwise, use/prompt for the password.
 416        */
 417       if (ccache_name) {
 418            printf(gettext(
 419                   "Authenticating as principal %s with existing credentials.\n"),
 420                   princstr);
 421            retval = kadm5_init_with_creds(princstr, cc,
 422                           kadmin_princ,
 423                           &params,
 424                           KADM5_STRUCT_VERSION,
 425                           KADM5_API_VERSION_2,
 426                           &handle);
 427       } else if (use_keytab) {
 428            if (keytab_name)
 429                printf(gettext("Authenticating as principal %s with keytab %s.\n"),
 430                       princstr, keytab_name);
 431            else
 432                printf(gettext(
 433                       "Authenticating as principal %s with default keytab.\n"),
 434                       princstr);
 435            retval = kadm5_init_with_skey(princstr, keytab_name,
 436                           kadmin_princ,
 437                           &params,
 438                           KADM5_STRUCT_VERSION,
 439                           KADM5_API_VERSION_2,
 440                           &handle);
 441       } else {
 442            printf(gettext("Authenticating as principal %s with password.\n"),
 443                   princstr);
 444            retval = kadm5_init_with_password(princstr, password,
 445                           kadmin_princ, &params,
 446                           KADM5_STRUCT_VERSION,
 447                           KADM5_API_VERSION_2,
 448                           &handle);
 449       }
 450       if (retval) {
 451               if (retval == KADM5_RPC_ERROR_CANTENCODEARGS ||
 452                   retval == KADM5_RPC_ERROR_CANTDECODEARGS) {
 453                       com_err(whoami, KADM5_RPC_ERROR,
 454                           gettext("while initializing %s interface"), whoami);
 455   
 456                       /* privacy-enabled mech probably not installed/configed */
 457                       com_err(whoami, retval, gettext("."), whoami);
 458               } else {
 459                       com_err(whoami, retval,
 460                           gettext("while initializing %s interface"), whoami);
 461           if (retval == KADM5_BAD_CLIENT_PARAMS ||
 462               retval == KADM5_BAD_SERVER_PARAMS)
 463                   usage(whoami);
 464           }
 465           exit(1);
 466       }
 467       free(princstr);
 468   
 469       if (retval = krb5_cc_close(context, cc)) {
 470           com_err(whoami, retval, gettext("while closing ccache %s"),
 471                   ccache_name);
 472           exit(1);
 473       }
 474       /* register the WRFILE keytab type and set it as the default */
 475       if (retval = krb5_kt_register(context, &krb5_ktf_writable_ops)) {
 476            com_err(whoami, retval,
 477               gettext("while registering writable key table functions"));
 478            exit(1);
 479       }
 480       {
 481           /*
 482            * XXX krb5_defkeyname is an internal library global and
 483            * should go away
 484            */
 485            extern char *krb5_defkeyname;
 486   
 487            krb5_defkeyname = DEFAULT_KEYTAB;
 488       }
 489 + 
 490 +     if ((retval = kadm5_init_iprop(handle)) != 0) {
 491 +         com_err(whoami, retval, gettext("while mapping update log"));
 492 +         exit(1);
 493 +     }
 494 + 
 495       /* Solaris kerberos: fix memory leak */
 496       if (kadmin_princ)
 497           free(kadmin_princ);
 498   
 499       return (query);
 500   }

 ----Unchanged portion omitted----