diff options
| author | Stanislav Sedov <stas@FreeBSD.org> | 2011-10-05 07:23:29 +0000 | 
|---|---|---|
| committer | Stanislav Sedov <stas@FreeBSD.org> | 2011-10-05 07:23:29 +0000 | 
| commit | 7c450da7b446c557e05f34a100b597800967d987 (patch) | |
| tree | 57a48e7e9b592f2d5b713e80a4455820625c2b7b /lib/hdb/keytab.c | |
| parent | b4e3a10e9339a8400197298021d6ca9b8e3aa039 (diff) | |
Diffstat (limited to 'lib/hdb/keytab.c')
| -rw-r--r-- | lib/hdb/keytab.c | 376 | 
1 files changed, 264 insertions, 112 deletions
| diff --git a/lib/hdb/keytab.c b/lib/hdb/keytab.c index e319bb503155..c72b797dab4d 100644 --- a/lib/hdb/keytab.c +++ b/lib/hdb/keytab.c @@ -1,53 +1,58 @@  /* - * Copyright (c) 1999 - 2002 Kungliga Tekniska Högskolan - * (Royal Institute of Technology, Stockholm, Sweden).  - * All rights reserved.  + * Copyright (c) 1999 - 2002 Kungliga Tekniska Högskolan + * (Royal Institute of Technology, Stockholm, Sweden). + * All rights reserved.   * - * Redistribution and use in source and binary forms, with or without  - * modification, are permitted provided that the following conditions  - * are met:  + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met:   * - * 1. Redistributions of source code must retain the above copyright  - *    notice, this list of conditions and the following disclaimer.  + * 1. Redistributions of source code must retain the above copyright + *    notice, this list of conditions and the following disclaimer.   * - * 2. Redistributions in binary form must reproduce the above copyright  - *    notice, this list of conditions and the following disclaimer in the  - *    documentation and/or other materials provided with the distribution.  + * 2. Redistributions in binary form must reproduce the above copyright + *    notice, this list of conditions and the following disclaimer in the + *    documentation and/or other materials provided with the distribution.   * - * 3. Neither the name of the Institute nor the names of its contributors  - *    may be used to endorse or promote products derived from this software  - *    without specific prior written permission.  + * 3. Neither the name of the Institute nor the names of its contributors + *    may be used to endorse or promote products derived from this software + *    without specific prior written permission.   * - * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND  - * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE  - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE  - * ARE DISCLAIMED.  IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE  - * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL  - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS  - * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)  - * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT  - * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY  - * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF  - * SUCH DAMAGE.  + * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED.  IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE.   */  #include "hdb_locl.h"  /* keytab backend for HDB databases */ -RCSID("$Id: keytab.c 18380 2006-10-09 12:36:40Z lha $"); -  struct hdb_data {      char *dbname;      char *mkey;  }; +struct hdb_cursor { +    HDB *db; +    hdb_entry_ex hdb_entry; +    int first, next; +    int key_idx; +}; +  /*   * the format for HDB keytabs is: - * HDB:[database:file:mkey] + * HDB:[HDBFORMAT:database-specific-data[:mkey=mkey-file]]   */ -static krb5_error_code +static krb5_error_code KRB5_CALLCONV  hdb_resolve(krb5_context context, const char *name, krb5_keytab id)  {      struct hdb_data *d; @@ -55,41 +60,38 @@ hdb_resolve(krb5_context context, const char *name, krb5_keytab id)      d = malloc(sizeof(*d));      if(d == NULL) { -	krb5_set_error_string(context, "malloc: out of memory"); +	krb5_set_error_message(context, ENOMEM, "malloc: out of memory");  	return ENOMEM;      }      db = name; -    mkey = strchr(name, ':'); -    if(mkey == NULL || mkey[1] == '\0') { +    mkey = strstr(name, ":mkey="); +    if(mkey == NULL || mkey[5] == '\0') {  	if(*name == '\0')  	    d->dbname = NULL;  	else {  	    d->dbname = strdup(name);  	    if(d->dbname == NULL) {  		free(d); -		krb5_set_error_string(context, "malloc: out of memory"); +		krb5_set_error_message(context, ENOMEM, "malloc: out of memory");  		return ENOMEM;  	    }  	}  	d->mkey = NULL;      } else { -	if((mkey - db) == 0) { -	    d->dbname = NULL; -	} else { -	    d->dbname = malloc(mkey - db + 1); -	    if(d->dbname == NULL) { -		free(d); -		krb5_set_error_string(context, "malloc: out of memory"); -		return ENOMEM; -	    } -	    memmove(d->dbname, db, mkey - db); -	    d->dbname[mkey - db] = '\0'; +	d->dbname = malloc(mkey - db + 1); +	if(d->dbname == NULL) { +	    free(d); +	    krb5_set_error_message(context, ENOMEM, "malloc: out of memory"); +	    return ENOMEM;  	} -	d->mkey = strdup(mkey + 1); +	memmove(d->dbname, db, mkey - db); +	d->dbname[mkey - db] = '\0'; + +	d->mkey = strdup(mkey + 5);  	if(d->mkey == NULL) {  	    free(d->dbname);  	    free(d); -	    krb5_set_error_string(context, "malloc: out of memory"); +	    krb5_set_error_message(context, ENOMEM, "malloc: out of memory");  	    return ENOMEM;  	}      } @@ -97,7 +99,7 @@ hdb_resolve(krb5_context context, const char *name, krb5_keytab id)      return 0;  } -static krb5_error_code +static krb5_error_code KRB5_CALLCONV  hdb_close(krb5_context context, krb5_keytab id)  {      struct hdb_data *d = id->data; @@ -108,76 +110,58 @@ hdb_close(krb5_context context, krb5_keytab id)      return 0;  } -static krb5_error_code  -hdb_get_name(krb5_context context,  -	     krb5_keytab id,  -	     char *name,  +static krb5_error_code KRB5_CALLCONV +hdb_get_name(krb5_context context, +	     krb5_keytab id, +	     char *name,  	     size_t namesize)  {      struct hdb_data *d = id->data; -    snprintf(name, namesize, "%s%s%s",  +    snprintf(name, namesize, "%s%s%s",  	     d->dbname ? d->dbname : "",  	     (d->dbname || d->mkey) ? ":" : "",  	     d->mkey ? d->mkey : "");      return 0;  } -static void -set_config (krb5_context context, -	    const krb5_config_binding *binding, -	    const char **dbname, -	    const char **mkey) -{ -    *dbname = krb5_config_get_string(context, binding, "dbname", NULL); -    *mkey   = krb5_config_get_string(context, binding, "mkey_file", NULL); -} -  /*   * try to figure out the database (`dbname') and master-key (`mkey')   * that should be used for `principal'.   */ -static void +static krb5_error_code  find_db (krb5_context context, -	 const char **dbname, -	 const char **mkey, +	 char **dbname, +	 char **mkey,  	 krb5_const_principal principal)  { -    const krb5_config_binding *top_bind = NULL; -    const krb5_config_binding *default_binding = NULL; -    const krb5_config_binding *db; -    krb5_realm *prealm = krb5_princ_realm(context, rk_UNCONST(principal)); +    krb5_const_realm realm = krb5_principal_get_realm(context, principal); +    krb5_error_code ret; +    struct hdb_dbinfo *head, *dbinfo = NULL;      *dbname = *mkey = NULL; -    while ((db = -	    krb5_config_get_next(context, -				 NULL, -				 &top_bind, -				 krb5_config_list, -				 "kdc", -				 "database", -				 NULL)) != NULL) { -	const char *p; -	 -	p = krb5_config_get_string (context, db, "realm", NULL); -	if (p == NULL) { -	    if(default_binding) { -		krb5_warnx(context, "WARNING: more than one realm-less " -			   "database specification"); -		krb5_warnx(context, "WARNING: using the first encountered"); -	    } else -		default_binding = db; -	} else if (strcmp (*prealm, p) == 0) { -	    set_config (context, db, dbname, mkey); +    ret = hdb_get_dbinfo(context, &head); +    if (ret) +	return ret; + +    while ((dbinfo = hdb_dbinfo_get_next(head, dbinfo)) != NULL) { +	const char *p = hdb_dbinfo_get_realm(context, dbinfo); +	if (p && strcmp (realm, p) == 0) { +	    p = hdb_dbinfo_get_dbname(context, dbinfo); +	    if (p) +		*dbname = strdup(p); +	    p = hdb_dbinfo_get_mkey_file(context, dbinfo); +	    if (p) +		*mkey = strdup(p);  	    break;  	}      } -    if (*dbname == NULL && default_binding != NULL) -	set_config (context, default_binding, dbname, mkey); +    hdb_free_dbinfo(context, &head);      if (*dbname == NULL) -	*dbname = HDB_DEFAULT_DB; +	*dbname = strdup(HDB_DEFAULT_DB); +    return 0;  }  /* @@ -185,7 +169,7 @@ find_db (krb5_context context,   * it in `entry'.  return 0 or an error code   */ -static krb5_error_code +static krb5_error_code KRB5_CALLCONV  hdb_get_entry(krb5_context context,  	      krb5_keytab id,  	      krb5_const_principal principal, @@ -196,34 +180,41 @@ hdb_get_entry(krb5_context context,      hdb_entry_ex ent;      krb5_error_code ret;      struct hdb_data *d = id->data; -    int i; -    HDB *db;      const char *dbname = d->dbname;      const char *mkey   = d->mkey; +    char *fdbname = NULL, *fmkey = NULL; +    HDB *db; +    size_t i;      memset(&ent, 0, sizeof(ent)); -    if (dbname == NULL) -	find_db (context, &dbname, &mkey, principal); +    if (dbname == NULL) { +	ret = find_db(context, &fdbname, &fmkey, principal); +	if (ret) +	    return ret; +	dbname = fdbname; +	mkey = fmkey; +    }      ret = hdb_create (context, &db, dbname);      if (ret) -	return ret; +	goto out2;      ret = hdb_set_master_keyfile (context, db, mkey);      if (ret) {  	(*db->hdb_destroy)(context, db); -	return ret; +	goto out2;      } -	 +      ret = (*db->hdb_open)(context, db, O_RDONLY, 0);      if (ret) {  	(*db->hdb_destroy)(context, db); -	return ret; +	goto out2;      } -    ret = (*db->hdb_fetch)(context, db, principal,  -			   HDB_F_DECRYPT| -			   HDB_F_GET_CLIENT|HDB_F_GET_SERVER|HDB_F_GET_KRBTGT, -			   &ent); + +    ret = (*db->hdb_fetch_kvno)(context, db, principal, +				HDB_F_DECRYPT|HDB_F_KVNO_SPECIFIED| +				HDB_F_GET_CLIENT|HDB_F_GET_SERVER|HDB_F_GET_KRBTGT, +				kvno, &ent);      if(ret == HDB_ERR_NOENTRY) {  	ret = KRB5_KT_NOTFOUND; @@ -231,7 +222,7 @@ hdb_get_entry(krb5_context context,      }else if(ret)  	goto out; -    if(kvno && ent.entry.kvno != kvno) { +    if(kvno && (krb5_kvno)ent.entry.kvno != kvno) {  	hdb_free_entry(context, &ent);   	ret = KRB5_KT_NOTFOUND;  	goto out; @@ -244,29 +235,190 @@ hdb_get_entry(krb5_context context,  	if(ent.entry.keys.val[i].key.keytype == enctype) {  	    krb5_copy_principal(context, principal, &entry->principal);  	    entry->vno = ent.entry.kvno; -	    krb5_copy_keyblock_contents(context,  -					&ent.entry.keys.val[i].key,  +	    krb5_copy_keyblock_contents(context, +					&ent.entry.keys.val[i].key,  					&entry->keyblock);  	    ret = 0;  	    break;  	}      }      hdb_free_entry(context, &ent); -out: + out:      (*db->hdb_close)(context, db);      (*db->hdb_destroy)(context, db); + out2: +    free(fdbname); +    free(fmkey); +    return ret; +} + +/* + * find the keytab entry in `id' for `principal, kvno, enctype' and return + * it in `entry'.  return 0 or an error code + */ + +static krb5_error_code KRB5_CALLCONV +hdb_start_seq_get(krb5_context context, +		  krb5_keytab id, +		  krb5_kt_cursor *cursor) +{ +    krb5_error_code ret; +    struct hdb_cursor *c; +    struct hdb_data *d = id->data; +    const char *dbname = d->dbname; +    const char *mkey   = d->mkey; +    HDB *db; + +    if (dbname == NULL) { +	/* +	 * We don't support enumerating without being told what +	 * backend to enumerate on +	 */ +  	ret = KRB5_KT_NOTFOUND; +	return ret; +    } + +    ret = hdb_create (context, &db, dbname); +    if (ret) +	return ret; +    ret = hdb_set_master_keyfile (context, db, mkey); +    if (ret) { +	(*db->hdb_destroy)(context, db); +	return ret; +    } + +    ret = (*db->hdb_open)(context, db, O_RDONLY, 0); +    if (ret) { +	(*db->hdb_destroy)(context, db); +	return ret; +    } + +    cursor->data = c = malloc (sizeof(*c)); +    if(c == NULL){ +	(*db->hdb_close)(context, db); +	(*db->hdb_destroy)(context, db); +	krb5_set_error_message(context, ENOMEM, "malloc: out of memory"); +	return ENOMEM; +    } + +    c->db = db; +    c->first = TRUE; +    c->next = TRUE; +    c->key_idx = 0; + +    cursor->data = c;      return ret;  } +static int KRB5_CALLCONV +hdb_next_entry(krb5_context context, +	       krb5_keytab id, +	       krb5_keytab_entry *entry, +	       krb5_kt_cursor *cursor) +{ +    struct hdb_cursor *c = cursor->data; +    krb5_error_code ret; + +    memset(entry, 0, sizeof(*entry)); + +    if (c->first) { +	c->first = FALSE; +	ret = (c->db->hdb_firstkey)(context, c->db, +				    HDB_F_DECRYPT| +				    HDB_F_GET_CLIENT|HDB_F_GET_SERVER|HDB_F_GET_KRBTGT, +				    &c->hdb_entry); +	if (ret == HDB_ERR_NOENTRY) +	    return KRB5_KT_END; +	else if (ret) +	    return ret; + +	if (c->hdb_entry.entry.keys.len == 0) +	    hdb_free_entry(context, &c->hdb_entry); +	else +	    c->next = FALSE; +    } + +    while (c->next) { +	ret = (c->db->hdb_nextkey)(context, c->db, +				   HDB_F_DECRYPT| +				   HDB_F_GET_CLIENT|HDB_F_GET_SERVER|HDB_F_GET_KRBTGT, +				   &c->hdb_entry); +	if (ret == HDB_ERR_NOENTRY) +	    return KRB5_KT_END; +	else if (ret) +	    return ret; + +	/* If no keys on this entry, try again */ +	if (c->hdb_entry.entry.keys.len == 0) +	    hdb_free_entry(context, &c->hdb_entry); +	else +	    c->next = FALSE; +    } + +    /* +     * Return next enc type (keytabs are one slot per key, while +     * hdb is one record per principal. +     */ + +    ret = krb5_copy_principal(context, +			      c->hdb_entry.entry.principal, +			      &entry->principal); +    if (ret) +	return ret; + +    entry->vno = c->hdb_entry.entry.kvno; +    ret = krb5_copy_keyblock_contents(context, +				      &c->hdb_entry.entry.keys.val[c->key_idx].key, +				      &entry->keyblock); +    if (ret) { +	krb5_free_principal(context, entry->principal); +	memset(entry, 0, sizeof(*entry)); +	return ret; +    } +    c->key_idx++; + +    /* +     * Once we get to the end of the list, signal that we want the +     * next entry +     */ + +    if ((size_t)c->key_idx == c->hdb_entry.entry.keys.len) { +	hdb_free_entry(context, &c->hdb_entry); +	c->next = TRUE; +	c->key_idx = 0; +    } + +    return 0; +} + + +static int KRB5_CALLCONV +hdb_end_seq_get(krb5_context context, +		krb5_keytab id, +		krb5_kt_cursor *cursor) +{ +    struct hdb_cursor *c = cursor->data; + +    if (!c->next) +	hdb_free_entry(context, &c->hdb_entry); + +    (c->db->hdb_close)(context, c->db); +    (c->db->hdb_destroy)(context, c->db); + +    free(c); +    return 0; +} +  krb5_kt_ops hdb_kt_ops = {      "HDB",      hdb_resolve,      hdb_get_name,      hdb_close, +    NULL,		/* destroy */      hdb_get_entry, -    NULL,		/* start_seq_get */ -    NULL,		/* next_entry */ -    NULL,		/* end_seq_get */ +    hdb_start_seq_get, +    hdb_next_entry, +    hdb_end_seq_get,      NULL,		/* add */      NULL		/* remove */  }; | 
