Пример #1
0
kadm5_ret_t
_kadm5_set_keys(kadm5_server_context *context,
		hdb_entry *ent,
		const char *password)
{
    Key *keys;
    size_t num_keys;
    kadm5_ret_t ret;

    ret = hdb_generate_key_set_password(context->context,
					ent->principal,
					password, &keys, &num_keys);
    if (ret)
	return ret;

    _kadm5_free_keys (context->context, ent->keys.len, ent->keys.val);
    ent->keys.val = keys;
    ent->keys.len = num_keys;

    hdb_entry_set_pw_change_time(context->context, ent, 0);

    if (krb5_config_get_bool_default(context->context, NULL, FALSE,
				     "kadmin", "save-password", NULL))
    {
	ret = hdb_entry_set_password(context->context, context->db,
				     ent, password);
	if (ret)
	    return ret;
    }

    return 0;
}
Пример #2
0
kadm5_ret_t
_kadm5_set_keys2(kadm5_server_context *context,
		 hdb_entry *ent,
		 int16_t n_key_data,
		 krb5_key_data *key_data)
{
    krb5_error_code ret;
    int i;
    unsigned len;
    Key *keys;

    len  = n_key_data;
    keys = malloc (len * sizeof(*keys));
    if (keys == NULL)
	return ENOMEM;

    _kadm5_init_keys (keys, len);

    for(i = 0; i < n_key_data; i++) {
	keys[i].mkvno = NULL;
	keys[i].key.keytype = key_data[i].key_data_type[0];
	ret = krb5_data_copy(&keys[i].key.keyvalue,
			     key_data[i].key_data_contents[0],
			     key_data[i].key_data_length[0]);
	if(ret)
	    goto out;
	if(key_data[i].key_data_ver == 2) {
	    Salt *salt;

	    salt = calloc(1, sizeof(*salt));
	    if(salt == NULL) {
		ret = ENOMEM;
		goto out;
	    }
	    keys[i].salt = salt;
	    salt->type = key_data[i].key_data_type[1];
	    krb5_data_copy(&salt->salt,
			   key_data[i].key_data_contents[1],
			   key_data[i].key_data_length[1]);
	} else
	    keys[i].salt = NULL;
    }
    _kadm5_free_keys (context->context, ent->keys.len, ent->keys.val);
    ent->keys.len = len;
    ent->keys.val = keys;

    hdb_entry_set_pw_change_time(context->context, ent, 0);
    hdb_entry_clear_password(context->context, ent);

    return 0;
 out:
    _kadm5_free_keys (context->context, len, keys);
    return ret;
}
Пример #3
0
static kadm5_ret_t
perform_tl_data(krb5_context context,
		HDB *db,
		hdb_entry_ex *ent,
		const krb5_tl_data *tl_data)
{
    kadm5_ret_t ret = 0;

    if (tl_data->tl_data_type == KRB5_TL_PASSWORD) {
	heim_utf8_string pw = tl_data->tl_data_contents;

	if (pw[tl_data->tl_data_length] != '\0')
	    return KADM5_BAD_TL_TYPE;

	ret = hdb_entry_set_password(context, db, &ent->entry, pw);

    } else if (tl_data->tl_data_type == KRB5_TL_LAST_PWD_CHANGE) {
	unsigned char *s;
	time_t t;

	if (tl_data->tl_data_length != 4)
	    return KADM5_BAD_TL_TYPE;

	s = tl_data->tl_data_contents;

	t = s[0] | (s[1] << 8) | (s[2] << 16) | (s[3] << 24);

	ret = hdb_entry_set_pw_change_time(context, &ent->entry, t);

    } else if (tl_data->tl_data_type == KRB5_TL_EXTENSION) {
	HDB_extension ext;

	ret = decode_HDB_extension(tl_data->tl_data_contents,
				   tl_data->tl_data_length,
				   &ext,
				   NULL);
	if (ret)
	    return KADM5_BAD_TL_TYPE;

	ret = hdb_replace_extension(context, &ent->entry, &ext);
	free_HDB_extension(&ext);
    } else {
	return KADM5_BAD_TL_TYPE;
    }
    return ret;
}
Пример #4
0
kadm5_ret_t
_kadm5_set_keys3(kadm5_server_context *context,
		 hdb_entry *ent,
		 int n_keys,
		 krb5_keyblock *keyblocks)
{
    krb5_error_code ret;
    int i;
    unsigned len;
    Key *keys;

    len  = n_keys;
    keys = malloc (len * sizeof(*keys));
    if (keys == NULL)
	return ENOMEM;

    _kadm5_init_keys (keys, len);

    for(i = 0; i < n_keys; i++) {
	keys[i].mkvno = NULL;
	ret = krb5_copy_keyblock_contents (context->context,
					   &keyblocks[i],
					   &keys[i].key);
	if(ret)
	    goto out;
	keys[i].salt = NULL;
    }
    _kadm5_free_keys (context->context, ent->keys.len, ent->keys.val);
    ent->keys.len = len;
    ent->keys.val = keys;

    hdb_entry_set_pw_change_time(context->context, ent, 0);
    hdb_entry_clear_password(context->context, ent);

    return 0;
 out:
    _kadm5_free_keys (context->context, len, keys);
    return ret;
}
Пример #5
0
kadm5_ret_t
_kadm5_set_keys_randomly (kadm5_server_context *context,
			  hdb_entry *ent,
			  krb5_keyblock **new_keys,
			  int *n_keys)
{
   krb5_keyblock *kblock = NULL;
   kadm5_ret_t ret = 0;
   int i, des_keyblock;
   size_t num_keys;
   Key *keys;

   ret = hdb_generate_key_set(context->context, ent->principal,
			       &keys, &num_keys, 1);
   if (ret)
	return ret;

   kblock = malloc(num_keys * sizeof(kblock[0]));
   if (kblock == NULL) {
	ret = ENOMEM;
	_kadm5_free_keys (context->context, num_keys, keys);
	return ret;
   }
   memset(kblock, 0, num_keys * sizeof(kblock[0]));

   des_keyblock = -1;
   for (i = 0; i < num_keys; i++) {

	/*
	 * To make sure all des keys are the the same we generate only
	 * the first one and then copy key to all other des keys.
	 */

	if (des_keyblock != -1 && is_des_key_p(keys[i].key.keytype)) {
	    ret = krb5_copy_keyblock_contents (context->context,
					       &kblock[des_keyblock],
					       &kblock[i]);
	    if (ret)
		goto out;
	    kblock[i].keytype = keys[i].key.keytype;
	} else {
	    ret = krb5_generate_random_keyblock (context->context,
						 keys[i].key.keytype,
						 &kblock[i]);
	    if (ret)
		goto out;

	    if (is_des_key_p(keys[i].key.keytype))
		des_keyblock = i;
	}

	ret = krb5_copy_keyblock_contents (context->context,
					   &kblock[i],
					   &keys[i].key);
	if (ret)
	    goto out;
   }

out:
   if(ret) {
	for (i = 0; i < num_keys; ++i)
	    krb5_free_keyblock_contents (context->context, &kblock[i]);
	free(kblock);
	_kadm5_free_keys (context->context, num_keys, keys);
	return ret;
   }

   _kadm5_free_keys (context->context, ent->keys.len, ent->keys.val);
   ent->keys.val = keys;
   ent->keys.len = num_keys;
   *new_keys     = kblock;
   *n_keys       = num_keys;

   hdb_entry_set_pw_change_time(context->context, ent, 0);
   hdb_entry_clear_password(context->context, ent);

   return 0;
}
Пример #6
0
/**
 * Server-side function to set new keys for a principal.
 */
kadm5_ret_t
kadm5_s_setkey_principal_3(void *server_handle,
			   krb5_principal princ,
			   krb5_boolean keepold,
			   int n_ks_tuple,
			   krb5_key_salt_tuple *ks_tuple,
			   krb5_keyblock *keyblocks, int n_keys)
{
    kadm5_server_context *context = server_handle;
    hdb_entry_ex ent;
    kadm5_ret_t ret = 0;

    memset(&ent, 0, sizeof(ent));
    if (!context->keep_open)
	ret = context->db->hdb_open(context->context, context->db, O_RDWR, 0);
    if (ret)
	return ret;

    ret = kadm5_log_init(context);
    if (ret) {
        if (!context->keep_open)
            context->db->hdb_close(context->context, context->db);
        return ret;
    }

    ret = context->db->hdb_fetch_kvno(context->context, context->db, princ,
				      HDB_F_GET_ANY|HDB_F_ADMIN_DATA, 0, &ent);
    if (ret) {
        (void) kadm5_log_end(context);
        if (!context->keep_open)
            context->db->hdb_close(context->context, context->db);
        return ret;
    }

    if (keepold) {
        ret = hdb_add_current_keys_to_history(context->context, &ent.entry);
    } else
	ret = hdb_clear_extension(context->context, &ent.entry,
				  choice_HDB_extension_data_hist_keys);

    /*
     * Though in practice all real calls to this function will pass an empty
     * ks_tuple, and cannot in any case employ any salts that require
     * additional data, we go the extra mile to set any requested salt type
     * along with a zero length salt value.  While we're at it we check that
     * each ks_tuple's enctype matches the corresponding key enctype.
     */
    if (ret == 0) {
	int i;

	free_Keys(&ent.entry.keys);
	for (i = 0; i < n_keys; ++i) {
	    Key k;
	    Salt s;

	    k.mkvno = 0;
	    k.key = keyblocks[i];
	    if (n_ks_tuple == 0)
		k.salt = 0;
	    else {
		if (ks_tuple[i].ks_enctype != keyblocks[i].keytype) {
		    ret = KADM5_SETKEY3_ETYPE_MISMATCH;
		    break;
		}
		s.type = ks_tuple[i].ks_salttype;
		s.salt.data = 0;
		s.opaque = 0;
		k.salt = &s;
	    }
	    if ((ret = add_Keys(&ent.entry.keys, &k)) != 0)
		break;
	}
    }

    if (ret == 0) {
	ent.entry.kvno++;
	ent.entry.flags.require_pwchange = 0;
	hdb_entry_set_pw_change_time(context->context, &ent.entry, 0);
	hdb_entry_clear_password(context->context, &ent.entry);

	if ((ret = hdb_seal_keys(context->context, context->db,
				 &ent.entry)) == 0
	    && (ret = _kadm5_set_modifier(context, &ent.entry)) == 0
	    && (ret = _kadm5_bump_pw_expire(context, &ent.entry)) == 0)
	    ret = kadm5_log_modify(context, &ent.entry,
                                   KADM5_ATTRIBUTES | KADM5_PRINCIPAL |
                                   KADM5_MOD_NAME | KADM5_MOD_TIME |
                                   KADM5_KEY_DATA | KADM5_KVNO |
                                   KADM5_PW_EXPIRATION | KADM5_TL_DATA);
    }

    hdb_free_entry(context->context, &ent);
    (void) kadm5_log_end(context);
    if (!context->keep_open)
	context->db->hdb_close(context->context, context->db);
    return _kadm5_error_code(ret);
}
Пример #7
0
/*
 * Construct an hdb_entry from a directory entry.
 */
static krb5_error_code
LDAP_message2entry(krb5_context context, HDB * db, LDAPMessage * msg,
		   hdb_entry_ex * ent)
{
    char *unparsed_name = NULL, *dn = NULL, *ntPasswordIN = NULL;
    char *samba_acct_flags = NULL;
    struct berval **keys;
    struct berval **vals;
    int tmp, tmp_time, i, ret, have_arcfour = 0;

    memset(ent, 0, sizeof(*ent));
    ent->entry.flags = int2HDBFlags(0);

    ret = LDAP_get_string_value(db, msg, "krb5PrincipalName", &unparsed_name);
    if (ret == 0) {
	ret = krb5_parse_name(context, unparsed_name, &ent->entry.principal);
	if (ret)
	    goto out;
    } else {
	ret = LDAP_get_string_value(db, msg, "uid",
				    &unparsed_name);
	if (ret == 0) {
	    ret = krb5_parse_name(context, unparsed_name, &ent->entry.principal);
	    if (ret)
		goto out;
	} else {
	    krb5_set_error_message(context, HDB_ERR_NOENTRY,
				   "hdb-ldap: ldap entry missing"
				  "principal name");
	    return HDB_ERR_NOENTRY;
	}
    }

    {
	int integer;
	ret = LDAP_get_integer_value(db, msg, "krb5KeyVersionNumber",
				     &integer);
	if (ret)
	    ent->entry.kvno = 0;
	else
	    ent->entry.kvno = integer;
    }

    keys = ldap_get_values_len(HDB2LDAP(db), msg, "krb5Key");
    if (keys != NULL) {
	int i;
	size_t l;

	ent->entry.keys.len = ldap_count_values_len(keys);
	ent->entry.keys.val = (Key *) calloc(ent->entry.keys.len, sizeof(Key));
	if (ent->entry.keys.val == NULL) {
	    ret = ENOMEM;
	    krb5_set_error_message(context, ret, "calloc: out of memory");
	    goto out;
	}
	for (i = 0; i < ent->entry.keys.len; i++) {
	    decode_Key((unsigned char *) keys[i]->bv_val,
		       (size_t) keys[i]->bv_len, &ent->entry.keys.val[i], &l);
	}
	ber_bvecfree(keys);
    } else {
#if 1
	/*
	 * This violates the ASN1 but it allows a principal to
	 * be related to a general directory entry without creating
	 * the keys. Hopefully it's OK.
	 */
	ent->entry.keys.len = 0;
	ent->entry.keys.val = NULL;
#else
	ret = HDB_ERR_NOENTRY;
	goto out;
#endif
    }

    vals = ldap_get_values_len(HDB2LDAP(db), msg, "krb5EncryptionType");
    if (vals != NULL) {
	int i;

	ent->entry.etypes = malloc(sizeof(*(ent->entry.etypes)));
	if (ent->entry.etypes == NULL) {
	    ret = ENOMEM;
	    krb5_set_error_message(context, ret,"malloc: out of memory");
	    goto out;
	}
	ent->entry.etypes->len = ldap_count_values_len(vals);
	ent->entry.etypes->val = calloc(ent->entry.etypes->len, sizeof(int));
	if (ent->entry.etypes->val == NULL) {
	    ret = ENOMEM;
	    krb5_set_error_message(context, ret, "malloc: out of memory");
	    ent->entry.etypes->len = 0;
	    goto out;
	}
	for (i = 0; i < ent->entry.etypes->len; i++) {
	    char *buf;

	    buf = malloc(vals[i]->bv_len + 1);
	    if (buf == NULL) {
		ret = ENOMEM;
		krb5_set_error_message(context, ret, "malloc: out of memory");
		goto out;
	    }
	    memcpy(buf, vals[i]->bv_val, vals[i]->bv_len);
	    buf[vals[i]->bv_len] = '\0';
	    ent->entry.etypes->val[i] = atoi(buf);
	    free(buf);
	}
	ldap_value_free_len(vals);
    }

    for (i = 0; i < ent->entry.keys.len; i++) {
	if (ent->entry.keys.val[i].key.keytype == ETYPE_ARCFOUR_HMAC_MD5) {
	    have_arcfour = 1;
	    break;
	}
    }

    /* manually construct the NT (type 23) key */
    ret = LDAP_get_string_value(db, msg, "sambaNTPassword", &ntPasswordIN);
    if (ret == 0 && have_arcfour == 0) {
	unsigned *etypes;
	Key *keys;
	int i;

	keys = realloc(ent->entry.keys.val,
		       (ent->entry.keys.len + 1) * sizeof(ent->entry.keys.val[0]));
	if (keys == NULL) {
	    free(ntPasswordIN);
	    ret = ENOMEM;
	    krb5_set_error_message(context, ret, "malloc: out of memory");
	    goto out;
	}
	ent->entry.keys.val = keys;
	memset(&ent->entry.keys.val[ent->entry.keys.len], 0, sizeof(Key));
	ent->entry.keys.val[ent->entry.keys.len].key.keytype = ETYPE_ARCFOUR_HMAC_MD5;
	ret = krb5_data_alloc (&ent->entry.keys.val[ent->entry.keys.len].key.keyvalue, 16);
	if (ret) {
	    krb5_set_error_message(context, ret, "malloc: out of memory");
	    free(ntPasswordIN);
	    ret = ENOMEM;
	    goto out;
	}
	ret = hex_decode(ntPasswordIN,
			 ent->entry.keys.val[ent->entry.keys.len].key.keyvalue.data, 16);
	ent->entry.keys.len++;

	if (ent->entry.etypes == NULL) {
	    ent->entry.etypes = malloc(sizeof(*(ent->entry.etypes)));
	    if (ent->entry.etypes == NULL) {
		ret = ENOMEM;
		krb5_set_error_message(context, ret, "malloc: out of memory");
		goto out;
	    }
	    ent->entry.etypes->val = NULL;
	    ent->entry.etypes->len = 0;
	}

	for (i = 0; i < ent->entry.etypes->len; i++)
	    if (ent->entry.etypes->val[i] == ETYPE_ARCFOUR_HMAC_MD5)
		break;
	/* If there is no ARCFOUR enctype, add one */
	if (i == ent->entry.etypes->len) {
	    etypes = realloc(ent->entry.etypes->val,
			     (ent->entry.etypes->len + 1) *
			     sizeof(ent->entry.etypes->val[0]));
	    if (etypes == NULL) {
		ret = ENOMEM;
		krb5_set_error_message(context, ret, "malloc: out of memory");
		goto out;			
	    }
	    ent->entry.etypes->val = etypes;
	    ent->entry.etypes->val[ent->entry.etypes->len] =
		ETYPE_ARCFOUR_HMAC_MD5;
	    ent->entry.etypes->len++;
	}
    }

    ret = LDAP_get_generalized_time_value(db, msg, "createTimestamp",
					  &ent->entry.created_by.time);
    if (ret)
	ent->entry.created_by.time = time(NULL);

    ent->entry.created_by.principal = NULL;

    ret = LDAP_get_string_value(db, msg, "creatorsName", &dn);
    if (ret == 0) {
	if (LDAP_dn2principal(context, db, dn, &ent->entry.created_by.principal)
	    != 0) {
	    ent->entry.created_by.principal = NULL;
	}
	free(dn);
    }

    ent->entry.modified_by = (Event *) malloc(sizeof(Event));
    if (ent->entry.modified_by == NULL) {
	ret = ENOMEM;
	krb5_set_error_message(context, ret, "malloc: out of memory");
	goto out;
    }
    ret = LDAP_get_generalized_time_value(db, msg, "modifyTimestamp",
					  &ent->entry.modified_by->time);
    if (ret == 0) {
	ret = LDAP_get_string_value(db, msg, "modifiersName", &dn);
	if (LDAP_dn2principal(context, db, dn, &ent->entry.modified_by->principal))
	    ent->entry.modified_by->principal = NULL;
	free(dn);
    } else {
	free(ent->entry.modified_by);
	ent->entry.modified_by = NULL;
    }

    ent->entry.valid_start = malloc(sizeof(*ent->entry.valid_start));
    if (ent->entry.valid_start == NULL) {
	ret = ENOMEM;
	krb5_set_error_message(context, ret, "malloc: out of memory");
	goto out;
    }
    ret = LDAP_get_generalized_time_value(db, msg, "krb5ValidStart",
					  ent->entry.valid_start);
    if (ret) {
	/* OPTIONAL */
	free(ent->entry.valid_start);
	ent->entry.valid_start = NULL;
    }

    ent->entry.valid_end = malloc(sizeof(*ent->entry.valid_end));
    if (ent->entry.valid_end == NULL) {
	ret = ENOMEM;
	krb5_set_error_message(context, ret, "malloc: out of memory");
	goto out;
    }
    ret = LDAP_get_generalized_time_value(db, msg, "krb5ValidEnd",
					  ent->entry.valid_end);
    if (ret) {
	/* OPTIONAL */
	free(ent->entry.valid_end);
	ent->entry.valid_end = NULL;
    }

    ret = LDAP_get_integer_value(db, msg, "sambaKickoffTime", &tmp_time);
    if (ret == 0) {
 	if (ent->entry.valid_end == NULL) {
 	    ent->entry.valid_end = malloc(sizeof(*ent->entry.valid_end));
 	    if (ent->entry.valid_end == NULL) {
 		ret = ENOMEM;
 		krb5_set_error_message(context, ret, "malloc: out of memory");
 		goto out;
 	    }
 	}
 	*ent->entry.valid_end = tmp_time;
    }

    ent->entry.pw_end = malloc(sizeof(*ent->entry.pw_end));
    if (ent->entry.pw_end == NULL) {
	ret = ENOMEM;
	krb5_set_error_message(context, ret, "malloc: out of memory");
	goto out;
    }
    ret = LDAP_get_generalized_time_value(db, msg, "krb5PasswordEnd",
					  ent->entry.pw_end);
    if (ret) {
	/* OPTIONAL */
	free(ent->entry.pw_end);
	ent->entry.pw_end = NULL;
    }

    ret = LDAP_get_integer_value(db, msg, "sambaPwdLastSet", &tmp_time);
    if (ret == 0) {
	time_t delta;

	if (ent->entry.pw_end == NULL) {
            ent->entry.pw_end = malloc(sizeof(*ent->entry.pw_end));
            if (ent->entry.pw_end == NULL) {
                ret = ENOMEM;
                krb5_set_error_message(context, ret, "malloc: out of memory");
                goto out;
            }
        }

	delta = krb5_config_get_time_default(context, NULL, 
					     365 * 24 * 60 * 60,
					     "kadmin",
					     "password_lifetime",
					     NULL);
        *ent->entry.pw_end = tmp_time + delta;
    }

    ret = LDAP_get_integer_value(db, msg, "sambaPwdMustChange", &tmp_time);
    if (ret == 0) {
	if (ent->entry.pw_end == NULL) {
	    ent->entry.pw_end = malloc(sizeof(*ent->entry.pw_end));
	    if (ent->entry.pw_end == NULL) {
		ret = ENOMEM;
		krb5_set_error_message(context, ret, "malloc: out of memory");
		goto out;
	    }
	}
	*ent->entry.pw_end = tmp_time;
    }

    /* OPTIONAL */
    ret = LDAP_get_integer_value(db, msg, "sambaPwdLastSet", &tmp_time);
    if (ret == 0)
	hdb_entry_set_pw_change_time(context, &ent->entry, tmp_time);

    {
	int max_life;

	ent->entry.max_life = malloc(sizeof(*ent->entry.max_life));
	if (ent->entry.max_life == NULL) {
	    ret = ENOMEM;
	    krb5_set_error_message(context, ret, "malloc: out of memory");
	    goto out;
	}
	ret = LDAP_get_integer_value(db, msg, "krb5MaxLife", &max_life);
	if (ret) {
	    free(ent->entry.max_life);
	    ent->entry.max_life = NULL;
	} else
	    *ent->entry.max_life = max_life;
    }

    {
	int max_renew;

	ent->entry.max_renew = malloc(sizeof(*ent->entry.max_renew));
	if (ent->entry.max_renew == NULL) {
	    ret = ENOMEM;
	    krb5_set_error_message(context, ret, "malloc: out of memory");
	    goto out;
	}
	ret = LDAP_get_integer_value(db, msg, "krb5MaxRenew", &max_renew);
	if (ret) {
	    free(ent->entry.max_renew);
	    ent->entry.max_renew = NULL;
	} else
	    *ent->entry.max_renew = max_renew;
    }

    ret = LDAP_get_integer_value(db, msg, "krb5KDCFlags", &tmp);
    if (ret)
	tmp = 0;

    ent->entry.flags = int2HDBFlags(tmp);

    /* Try and find Samba flags to put into the mix */
    ret = LDAP_get_string_value(db, msg, "sambaAcctFlags", &samba_acct_flags);
    if (ret == 0) {
	/* parse the [UXW...] string:
	
	   'N'    No password	
	   'D'    Disabled	
	   'H'    Homedir required	
	   'T'    Temp account.	
	   'U'    User account (normal) 	
	   'M'    MNS logon user account - what is this ? 	
	   'W'    Workstation account	
	   'S'    Server account 	
	   'L'    Locked account	
	   'X'    No Xpiry on password 	
	   'I'    Interdomain trust account	
	
	*/	
	
	int i;
	int flags_len = strlen(samba_acct_flags);

	if (flags_len < 2)
	    goto out2;

	if (samba_acct_flags[0] != '['
	    || samba_acct_flags[flags_len - 1] != ']')
	    goto out2;

	/* Allow forwarding */
	if (samba_forwardable)
	    ent->entry.flags.forwardable = TRUE;

	for (i=0; i < flags_len; i++) {
	    switch (samba_acct_flags[i]) {
	    case ' ':
	    case '[':
	    case ']':
		break;
	    case 'N':
		/* how to handle no password in kerberos? */
		break;
	    case 'D':
		ent->entry.flags.invalid = TRUE;
		break;
	    case 'H':
		break;
	    case 'T':
		/* temp duplicate */
		ent->entry.flags.invalid = TRUE;
		break;
	    case 'U':
		ent->entry.flags.client = TRUE;
		break;
	    case 'M':
		break;
	    case 'W':
	    case 'S':
		ent->entry.flags.server = TRUE;
		ent->entry.flags.client = TRUE;
		break;
	    case 'L':
		ent->entry.flags.invalid = TRUE;
		break;
	    case 'X':
		if (ent->entry.pw_end) {
		    free(ent->entry.pw_end);
		    ent->entry.pw_end = NULL;
		}
		break;
	    case 'I':
		ent->entry.flags.server = TRUE;
		ent->entry.flags.client = TRUE;
		break;
	    }
	}
    out2:
	free(samba_acct_flags);
    }

    ret = 0;

out:
    if (unparsed_name)
	free(unparsed_name);

    if (ret)
	hdb_free_entry(context, ent);

    return ret;
}