]> git.decadent.org.uk Git - nfs-utils.git/blobdiff - utils/gssd/krb5_util.c
Imported upstream 1.2.6
[nfs-utils.git] / utils / gssd / krb5_util.c
index dccbeb63ad6478b26d8b6a2151625af1a86ca87a..887d118f3b19277196dcf75b5c532cb3c3376e92 100644 (file)
 /* Global list of principals/cache file names for machine credentials */
 struct gssd_k5_kt_princ *gssd_k5_kt_princ_list = NULL;
 
+#ifdef HAVE_SET_ALLOWABLE_ENCTYPES
+int limit_to_legacy_enctypes = 0;
+#endif
+
 /*==========================*/
 /*===  Internal routines ===*/
 /*==========================*/
@@ -224,6 +228,13 @@ gssd_find_existing_krb5_ccache(uid_t uid, char *dirname, struct dirent **d)
                                free(namelist[i]);
                                continue;
                        }
+                       if (uid == 0 && !root_uses_machine_creds && 
+                               strstr(namelist[i]->d_name, "_machine_")) {
+                               printerr(3, "CC file '%s' not available to root\n",
+                                        statname);
+                               free(namelist[i]);
+                               continue;
+                       }
                        if (!query_krb5_ccache(buf, &princname, &realm)) {
                                printerr(3, "CC file '%s' is expired or corrupt\n",
                                         statname);
@@ -606,24 +617,32 @@ out:
  * and has *any* instance (hostname), return 1.
  * Otherwise return 0, indicating no match.
  */
+#ifdef HAVE_KRB5
 static int
-realm_and_service_match(krb5_context context, krb5_principal p,
-                       const char *realm, const char *service)
+realm_and_service_match(krb5_principal p, const char *realm, const char *service)
 {
-#ifdef HAVE_KRB5
        /* Must have two components */
        if (p->length != 2)
                return 0;
+
        if ((strlen(realm) == p->realm.length)
            && (strncmp(realm, p->realm.data, p->realm.length) == 0)
            && (strlen(service) == p->data[0].length)
            && (strncmp(service, p->data[0].data, p->data[0].length) == 0))
                return 1;
+
+       return 0;
+}
 #else
+static int
+realm_and_service_match(krb5_context context, krb5_principal p,
+                       const char *realm, const char *service)
+{
        const char *name, *inst;
 
        if (p->name.name_string.len != 2)
                return 0;
+
        name = krb5_principal_get_comp_string(context, p, 0);
        inst = krb5_principal_get_comp_string(context, p, 1);
        if (name == NULL || inst == NULL)
@@ -631,9 +650,10 @@ realm_and_service_match(krb5_context context, krb5_principal p,
        if ((strcmp(realm, p->realm) == 0)
            && (strcmp(service, name) == 0))
                return 1;
-#endif
+
        return 0;
 }
+#endif
 
 /*
  * Search the given keytab file looking for an entry with the given
@@ -655,7 +675,7 @@ gssd_search_krb5_keytab(krb5_context context, krb5_keytab kt,
        krb5_kt_cursor cursor;
        krb5_error_code code;
        struct gssd_k5_kt_princ *ple;
-       int retval = -1;
+       int retval = -1, status;
        char kt_name[BUFSIZ];
        char *pname;
        char *k5err = NULL;
@@ -698,8 +718,12 @@ gssd_search_krb5_keytab(krb5_context context, krb5_keytab kt,
                printerr(4, "Processing keytab entry for principal '%s'\n",
                         pname);
                /* Use the first matching keytab entry found */
-               if ((realm_and_service_match(context, kte->principal, realm,
-                                            service))) {
+#ifdef HAVE_KRB5
+               status = realm_and_service_match(kte->principal, realm, service);
+#else
+               status = realm_and_service_match(context, kte->principal, realm, service);
+#endif
+               if (status) {
                        printerr(4, "We WILL use this entry (%s)\n", pname);
                        ple = get_ple_by_princ(context, kte->principal);
                        /*
@@ -748,6 +772,7 @@ find_keytab_entry(krb5_context context, krb5_keytab kt, const char *hostname,
        krb5_error_code code;
        char **realmnames = NULL;
        char myhostname[NI_MAXHOST], targethostname[NI_MAXHOST];
+       char myhostad[NI_MAXHOST+1];
        int i, j, retval;
        char *default_realm = NULL;
        char *realm;
@@ -769,6 +794,14 @@ find_keytab_entry(krb5_context context, krb5_keytab kt, const char *hostname,
                printerr(1, "%s while getting local hostname\n", k5err);
                goto out;
        }
+
+       /* Compute the active directory machine name HOST$ */
+       strcpy(myhostad, myhostname);
+       for (i = 0; myhostad[i] != 0; ++i)
+               myhostad[i] = toupper(myhostad[i]);
+       myhostad[i] = '$';
+       myhostad[i+1] = 0;
+
        retval = get_full_hostname(myhostname, myhostname, sizeof(myhostname));
        if (retval)
                goto out;
@@ -813,32 +846,47 @@ find_keytab_entry(krb5_context context, krb5_keytab kt, const char *hostname,
                if (strcmp(realm, default_realm) == 0)
                        tried_default = 1;
                for (j = 0; svcnames[j] != NULL; j++) {
-                       code = krb5_build_principal_ext(context, &princ,
-                                                       strlen(realm),
-                                                       realm,
-                                                       strlen(svcnames[j]),
-                                                       svcnames[j],
-                                                       strlen(myhostname),
-                                                       myhostname,
-                                                       NULL);
+                       char spn[300];
+
+                       /*
+                        * The special svcname "$" means 'try the active
+                        * directory machine account'
+                        */
+                       if (strcmp(svcnames[j],"$") == 0) {
+                               snprintf(spn, sizeof(spn), "%s@%s", myhostad, realm);
+                               code = krb5_build_principal_ext(context, &princ,
+                                                               strlen(realm),
+                                                               realm,
+                                                               strlen(myhostad),
+                                                               myhostad,
+                                                               NULL);
+                       } else {
+                               snprintf(spn, sizeof(spn), "%s/%s@%s",
+                                        svcnames[j], myhostname, realm);
+                               code = krb5_build_principal_ext(context, &princ,
+                                                               strlen(realm),
+                                                               realm,
+                                                               strlen(svcnames[j]),
+                                                               svcnames[j],
+                                                               strlen(myhostname),
+                                                               myhostname,
+                                                               NULL);
+                       }
+
                        if (code) {
                                k5err = gssd_k5_err_msg(context, code);
-                               printerr(1, "%s while building principal for "
-                                        "'%s/%s@%s'\n", k5err, svcnames[j],
-                                        myhostname, realm);
+                               printerr(1, "%s while building principal for '%s'\n",
+                                        k5err, spn);
                                continue;
                        }
                        code = krb5_kt_get_entry(context, kt, princ, 0, 0, kte);
                        krb5_free_principal(context, princ);
                        if (code) {
                                k5err = gssd_k5_err_msg(context, code);
-                               printerr(3, "%s while getting keytab entry for "
-                                        "'%s/%s@%s'\n", k5err, svcnames[j],
-                                        myhostname, realm);
+                               printerr(3, "%s while getting keytab entry for '%s'\n",
+                                        k5err, spn);
                        } else {
-                               printerr(3, "Success getting keytab entry for "
-                                        "'%s/%s@%s'\n",
-                                        svcnames[j], myhostname, realm);
+                               printerr(3, "Success getting keytab entry for '%s'\n",spn);
                                retval = 0;
                                goto out;
                        }
@@ -850,6 +898,8 @@ find_keytab_entry(krb5_context context, krb5_keytab kt, const char *hostname,
                 */
                for (j = 0; svcnames[j] != NULL; j++) {
                        int found = 0;
+                       if (strcmp(svcnames[j],"$") == 0)
+                               continue;
                        code = gssd_search_krb5_keytab(context, kt, realm,
                                                       svcnames[j], &found, kte);
                        if (!code && found) {
@@ -1140,7 +1190,7 @@ gssd_refresh_krb5_machine_credential(char *hostname,
        krb5_keytab kt = NULL;;
        int retval = 0;
        char *k5err = NULL;
-       const char *svcnames[4] = { "root", "nfs", "host", NULL };
+       const char *svcnames[5] = { "$", "root", "nfs", "host", NULL };
 
        /*
         * If a specific service name was specified, use it.
@@ -1265,7 +1315,7 @@ gssd_k5_get_default_realm(char **def_realm)
  */
 
 int
-limit_krb5_enctypes(struct rpc_gss_sec *sec, uid_t uid)
+limit_krb5_enctypes(struct rpc_gss_sec *sec)
 {
        u_int maj_stat, min_stat;
        gss_cred_id_t credh;
@@ -1296,7 +1346,7 @@ limit_krb5_enctypes(struct rpc_gss_sec *sec, uid_t uid)
         * If we failed for any reason to produce global
         * list of supported enctypes, use local default here.
         */
-       if (krb5_enctypes == NULL)
+       if (krb5_enctypes == NULL || limit_to_legacy_enctypes)
                maj_stat = gss_set_allowable_enctypes(&min_stat, credh,
                                        &krb5oid, num_enctypes, enctypes);
        else