Blame library/adutil.c

Packit 8586cb
/*
Packit 8586cb
 * adcli
Packit 8586cb
 *
Packit 8586cb
 * Copyright (C) 2012 Red Hat Inc.
Packit 8586cb
 *
Packit 8586cb
 * This program is free software; you can redistribute it and/or modify
Packit 8586cb
 * it under the terms of the GNU Lesser General Public License as
Packit 8586cb
 * published by the Free Software Foundation; either version 2.1 of
Packit 8586cb
 * the License, or (at your option) any later version.
Packit 8586cb
 *
Packit 8586cb
 * This program is distributed in the hope that it will be useful, but
Packit 8586cb
 * WITHOUT ANY WARRANTY; without even the implied warranty of
Packit 8586cb
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
Packit 8586cb
 * Lesser General Public License for more details.
Packit 8586cb
 *
Packit 8586cb
 * You should have received a copy of the GNU Lesser General Public
Packit 8586cb
 * License along with this program; if not, write to the Free Software
Packit 8586cb
 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
Packit 8586cb
 * MA 02110-1301 USA
Packit 8586cb
 *
Packit 8586cb
 * Author: Stef Walter <stefw@gnome.org>
Packit 8586cb
 */
Packit 8586cb
Packit 8586cb
#include "config.h"
Packit 8586cb
Packit 8586cb
#include "adcli.h"
Packit 8586cb
#include "adprivate.h"
Packit 8586cb
#include "seq.h"
Packit 8586cb
Packit 8586cb
#include <assert.h>
Packit 8586cb
#include <ctype.h>
Packit 8586cb
#include <errno.h>
Packit 8586cb
#include <stdio.h>
Packit 8586cb
#include <stdlib.h>
Packit 8586cb
#include <string.h>
Packit 8586cb
#include <unistd.h>
Packit 8586cb
#include <stdint.h>
Packit 8586cb
#include <time.h>
Packit Service cb5865
#include <sys/wait.h>
Packit 8586cb
Packit 8586cb
static adcli_message_func message_func = NULL;
Packit 8586cb
static char last_error[2048] = { 0, };
Packit 8586cb
Packit 8586cb
void
Packit 8586cb
_adcli_precond_failed (const char *message,
Packit 8586cb
                       ...)
Packit 8586cb
{
Packit 8586cb
	va_list va;
Packit 8586cb
	const char *env;
Packit 8586cb
Packit 8586cb
	va_start (va, message);
Packit 8586cb
	vfprintf (stderr, message, va);
Packit 8586cb
	va_end (va);
Packit 8586cb
Packit 8586cb
	env = getenv ("ADCLI_STRICT");
Packit 8586cb
	if (env != NULL && env[0] != '\0')
Packit 8586cb
		abort ();
Packit 8586cb
Packit 8586cb
	/* Let coverity know we're not supposed to return from here */
Packit 8586cb
#ifdef __COVERITY__
Packit 8586cb
	abort();
Packit 8586cb
#endif
Packit 8586cb
}
Packit 8586cb
Packit 8586cb
const char *
Packit 8586cb
adcli_result_to_string (adcli_result res)
Packit 8586cb
{
Packit 8586cb
	switch (res) {
Packit 8586cb
	case ADCLI_SUCCESS:
Packit 8586cb
		return "Success";
Packit 8586cb
	case ADCLI_ERR_UNEXPECTED:
Packit 8586cb
		return "Unexpected or internal system error";
Packit 8586cb
	case ADCLI_ERR_DIRECTORY:
Packit 8586cb
		return "Problem with the Active Directory or connecting to it";
Packit 8586cb
	case ADCLI_ERR_CREDENTIALS:
Packit 8586cb
		return "The administrative credentials are invalid or access is denied";
Packit 8586cb
	case ADCLI_ERR_CONFIG:
Packit 8586cb
		return "The local system has an invalid configuration";
Packit 8586cb
	case ADCLI_ERR_FAIL:
Packit 8586cb
		return "Generic failure";
Packit 8586cb
	}
Packit 8586cb
Packit 8586cb
	return_val_if_reached ("Unknown error");
Packit 8586cb
}
Packit 8586cb
Packit 8586cb
static void
Packit 8586cb
messagev (adcli_message_type type,
Packit 8586cb
          const char *format,
Packit 8586cb
          va_list va)
Packit 8586cb
{
Packit 8586cb
	char buffer[sizeof (last_error)];
Packit 8586cb
	char *where = buffer;
Packit 8586cb
	int ret;
Packit 8586cb
Packit 8586cb
	if (type == ADCLI_MESSAGE_ERROR)
Packit 8586cb
		where = last_error;
Packit 8586cb
	else if (message_func == NULL)
Packit 8586cb
		return;
Packit 8586cb
Packit 8586cb
	ret = vsnprintf (where, sizeof (buffer), format, va);
Packit 8586cb
	return_if_fail (ret >= 0);
Packit 8586cb
Packit 8586cb
	if (message_func != NULL)
Packit 8586cb
		(message_func) (type, where);
Packit 8586cb
}
Packit 8586cb
Packit 8586cb
void
Packit 8586cb
_adcli_err (const char *format,
Packit 8586cb
            ...)
Packit 8586cb
{
Packit 8586cb
	va_list va;
Packit 8586cb
	va_start (va, format);
Packit 8586cb
	messagev (ADCLI_MESSAGE_ERROR, format, va);
Packit 8586cb
	va_end (va);
Packit 8586cb
}
Packit 8586cb
Packit 8586cb
void
Packit 8586cb
_adcli_warn (const char *format,
Packit 8586cb
             ...)
Packit 8586cb
{
Packit 8586cb
	va_list va;
Packit 8586cb
	va_start (va, format);
Packit 8586cb
	messagev (ADCLI_MESSAGE_ERROR, format, va);
Packit 8586cb
	va_end (va);
Packit 8586cb
}
Packit 8586cb
Packit 8586cb
void
Packit 8586cb
_adcli_info (const char *format,
Packit 8586cb
             ...)
Packit 8586cb
{
Packit 8586cb
	va_list va;
Packit 8586cb
	va_start (va, format);
Packit 8586cb
	messagev (ADCLI_MESSAGE_INFO, format, va);
Packit 8586cb
	va_end (va);
Packit 8586cb
}
Packit 8586cb
Packit 8586cb
void
Packit 8586cb
adcli_set_message_func (adcli_message_func func)
Packit 8586cb
{
Packit 8586cb
	message_func = func;
Packit 8586cb
}
Packit 8586cb
Packit 8586cb
const char *
Packit 8586cb
adcli_get_last_error (void)
Packit 8586cb
{
Packit 8586cb
	return last_error[0] ? last_error : NULL;
Packit 8586cb
}
Packit 8586cb
Packit 8586cb
void
Packit 8586cb
adcli_clear_last_error (void)
Packit 8586cb
{
Packit 8586cb
	last_error[0] = '\0';
Packit 8586cb
}
Packit 8586cb
Packit 8586cb
void
Packit 8586cb
_adcli_strv_free (char **strv)
Packit 8586cb
{
Packit 8586cb
	seq_free (strv, free);
Packit 8586cb
}
Packit 8586cb
Packit 8586cb
char **
Packit 8586cb
_adcli_strv_dup (char **strv)
Packit 8586cb
{
Packit 8586cb
	int count;
Packit 8586cb
Packit 8586cb
	if (!strv)
Packit 8586cb
		return NULL;
Packit 8586cb
Packit 8586cb
	count = seq_count (strv);
Packit 8586cb
	return seq_dup (strv, &count, (seq_copy)strdup);
Packit 8586cb
}
Packit 8586cb
Packit 8586cb
char *
Packit 8586cb
_adcli_strv_join (char **strv,
Packit 8586cb
                  const char *delim)
Packit 8586cb
{
Packit 8586cb
	char *result = NULL;
Packit 8586cb
	int at = 0;
Packit 8586cb
	int dlen;
Packit 8586cb
	int slen;
Packit 8586cb
	int i;
Packit 8586cb
Packit 8586cb
	dlen = strlen (delim);
Packit 8586cb
	for (i = 0; strv && strv[i] != NULL; i++) {
Packit 8586cb
		slen = strlen (strv[i]);
Packit 8586cb
		result = realloc (result, at + dlen + slen + 1);
Packit 8586cb
		return_val_if_fail (result != NULL, NULL);
Packit 8586cb
		if (at != 0) {
Packit 8586cb
			memcpy (result + at, delim, dlen);
Packit 8586cb
			at += dlen;
Packit 8586cb
		}
Packit 8586cb
Packit 8586cb
		memcpy (result + at, strv[i], slen);
Packit 8586cb
		at += slen;
Packit 8586cb
		result[at] = '\0';
Packit 8586cb
	}
Packit 8586cb
Packit 8586cb
	return result;
Packit 8586cb
}
Packit 8586cb
Packit 8586cb
int
Packit 8586cb
_adcli_strv_len (char **strv)
Packit 8586cb
{
Packit 8586cb
	return seq_count (strv);
Packit 8586cb
}
Packit 8586cb
Packit 8586cb
char **
Packit 8586cb
_adcli_strv_add (char **strv,
Packit 8586cb
                 char *string,
Packit 8586cb
                 int *length)
Packit 8586cb
{
Packit 8586cb
	int len;
Packit 8586cb
Packit 8586cb
	return_val_if_fail (string != NULL, strv);
Packit 8586cb
Packit 8586cb
	if (!length) {
Packit 8586cb
		len = seq_count (strv);
Packit 8586cb
		length = &len;
Packit 8586cb
	}
Packit 8586cb
Packit 8586cb
	return seq_push (strv, length, string);
Packit 8586cb
}
Packit 8586cb
Packit Service cc4392
int
Packit Service 09c7c8
_adcli_strv_has_ex (char **strv,
Packit Service 09c7c8
                    const char *str,
Packit Service 09c7c8
                    int (* compare) (const char *match, const char*value))
Packit Service 09c7c8
{
Packit Service 09c7c8
	int i;
Packit Service 09c7c8
Packit Service 09c7c8
	for (i = 0; strv && strv[i] != NULL; i++) {
Packit Service 09c7c8
		if (compare (strv[i], str) == 0)
Packit Service 09c7c8
			return 1;
Packit Service 09c7c8
	}
Packit Service 09c7c8
Packit Service 09c7c8
	return 0;
Packit Service 09c7c8
}
Packit Service 09c7c8
Packit Service 09c7c8
char **
Packit Service 09c7c8
_adcli_strv_add_unique (char **strv,
Packit Service 09c7c8
                        char *string,
Packit Service 09c7c8
                        int *length,
Packit Service 09c7c8
                        bool case_sensitive)
Packit Service 09c7c8
{
Packit Service 09c7c8
	if (_adcli_strv_has_ex (strv, string, case_sensitive ? strcmp : strcasecmp) == 1) {
Packit Service 09c7c8
		return strv;
Packit Service 09c7c8
	}
Packit Service 09c7c8
Packit Service 09c7c8
	return _adcli_strv_add (strv, string, length);
Packit Service 09c7c8
}
Packit Service 09c7c8
Packit Service a39e32
#define discard_const(ptr) ((void *)((uintptr_t)(ptr)))
Packit Service a39e32
Packit Service a39e32
void
Packit Service a39e32
_adcli_strv_remove_unsorted (char **strv,
Packit Service a39e32
                             const char *string,
Packit Service a39e32
                             int *length)
Packit Service a39e32
{
Packit Service a39e32
	int len;
Packit Service a39e32
Packit Service a39e32
	return_if_fail (string != NULL);
Packit Service a39e32
Packit Service a39e32
	if (!length) {
Packit Service a39e32
		len = seq_count (strv);
Packit Service a39e32
		length = &len;
Packit Service a39e32
	}
Packit Service a39e32
Packit Service a39e32
	return seq_remove_unsorted (strv, length, discard_const (string),
Packit Service a39e32
	                            (seq_compar)strcasecmp, free);
Packit Service a39e32
}
Packit Service a39e32
Packit 02606d
int
Packit Service 959362
_adcli_strv_has (char **strv,
Packit Service 959362
                 const char *str)
Packit 41f04b
{
Packit Service 09c7c8
	return _adcli_strv_has_ex (strv, str, strcmp);
Packit 41f04b
}
Packit 41f04b
Packit 8586cb
void
Packit 8586cb
_adcli_str_up (char *str)
Packit 8586cb
{
Packit 8586cb
	while (*str != '\0') {
Packit 8586cb
		*str = toupper (*str);
Packit 8586cb
		str++;
Packit 8586cb
	}
Packit 8586cb
}
Packit 8586cb
Packit 8586cb
int
Packit 8586cb
_adcli_str_is_up (const char *str)
Packit 8586cb
{
Packit 8586cb
	while (*str != '\0') {
Packit 8586cb
		if (*str != toupper (*str))
Packit 8586cb
			return 0;
Packit 8586cb
		str++;
Packit 8586cb
	}
Packit 8586cb
	return 1;
Packit 8586cb
}
Packit 8586cb
Packit 8586cb
void
Packit 8586cb
_adcli_str_down (char *str)
Packit 8586cb
{
Packit 8586cb
	while (*str != '\0') {
Packit 8586cb
		*str = tolower (*str);
Packit 8586cb
		str++;
Packit 8586cb
	}
Packit 8586cb
}
Packit 8586cb
Packit 8586cb
void
Packit 8586cb
_adcli_str_set (char **field,
Packit 8586cb
                const char *value)
Packit 8586cb
{
Packit 8586cb
	char *newval = NULL;
Packit 8586cb
Packit 8586cb
	if (value) {
Packit 8586cb
		newval = strdup (value);
Packit 8586cb
		return_if_fail (newval != NULL);
Packit 8586cb
	}
Packit 8586cb
Packit 8586cb
	free (*field);
Packit 8586cb
	*field = newval;
Packit 8586cb
}
Packit 8586cb
Packit 8586cb
void
Packit 8586cb
_adcli_strv_set (char ***field,
Packit 8586cb
                 const char **value)
Packit 8586cb
{
Packit 8586cb
	char **newval = NULL;
Packit 8586cb
Packit 8586cb
	if (value) {
Packit 8586cb
		newval = _adcli_strv_dup ((char **)value);
Packit 8586cb
		return_if_fail (newval != NULL);
Packit 8586cb
	}
Packit 8586cb
Packit 8586cb
	_adcli_strv_free (*field);
Packit 8586cb
	*field = newval;
Packit 8586cb
}
Packit 8586cb
Packit 8586cb
char *
Packit Service d2400d
_adcli_bin_sid_to_str (const uint8_t *data,
Packit Service d2400d
                       size_t len)
Packit Service d2400d
{
Packit Service d2400d
	uint8_t sid_rev_num;
Packit Service d2400d
	int8_t num_auths;
Packit Service d2400d
	uint8_t id_auth[6];
Packit Service d2400d
	uint32_t id_auth_val;
Packit Service d2400d
	uint32_t sub_auths[15];
Packit Service d2400d
	uint32_t val;
Packit Service d2400d
	size_t p = 0;
Packit Service d2400d
	size_t c;
Packit Service d2400d
	int nc;
Packit Service d2400d
	char *sid_buf;
Packit Service d2400d
	size_t sid_buf_len;
Packit Service d2400d
Packit Service d2400d
	if (data == NULL || len < 8) {
Packit Service d2400d
		return NULL;
Packit Service d2400d
	}
Packit Service d2400d
Packit Service d2400d
	sid_rev_num = (uint8_t) data [p];
Packit Service d2400d
	p++;
Packit Service d2400d
Packit Service d2400d
	num_auths = (int8_t) data[p];
Packit Service d2400d
	p++;
Packit Service d2400d
Packit Service d2400d
	if (num_auths > 15 || len < 8 + (num_auths * sizeof (uint32_t))) {
Packit Service d2400d
		return NULL;
Packit Service d2400d
	}
Packit Service d2400d
Packit Service d2400d
	for (c = 0; c < 6; c++) {
Packit Service d2400d
		id_auth[c] = (uint8_t) data[p];
Packit Service d2400d
		p++;
Packit Service d2400d
	}
Packit Service d2400d
Packit Service d2400d
	/* Only 32bits are used for the string representation */
Packit Service d2400d
	id_auth_val = (id_auth[2] << 24) +
Packit Service d2400d
	              (id_auth[3] << 16) +
Packit Service d2400d
	              (id_auth[4] << 8) +
Packit Service d2400d
	              (id_auth[5]);
Packit Service d2400d
Packit Service d2400d
	for (c = 0; c < num_auths; c++) {
Packit Service d2400d
		memcpy (&val, data + p, sizeof (uint32_t));
Packit Service d2400d
		sub_auths[c] = le32toh (val);
Packit Service d2400d
Packit Service d2400d
		p += sizeof (uint32_t);
Packit Service d2400d
	}
Packit Service d2400d
Packit Service d2400d
	sid_buf_len = 17 + (num_auths * 11);
Packit Service d2400d
	sid_buf = calloc (1, sid_buf_len);
Packit Service d2400d
	if (sid_buf == NULL) {
Packit Service d2400d
		return NULL;
Packit Service d2400d
	}
Packit Service d2400d
Packit Service d2400d
	nc = snprintf (sid_buf, sid_buf_len, "S-%u-%lu", sid_rev_num,
Packit Service d2400d
	              (unsigned long) id_auth_val);
Packit Service d2400d
	if (nc < 0 || nc >= sid_buf_len) {
Packit Service d2400d
		free (sid_buf);
Packit Service d2400d
		return NULL;
Packit Service d2400d
	}
Packit Service d2400d
Packit Service d2400d
	p = 0;
Packit Service d2400d
	for (c = 0; c < num_auths; c++) {
Packit Service d2400d
		p += nc;
Packit Service d2400d
		sid_buf_len -= nc;
Packit Service d2400d
Packit Service d2400d
		nc = snprintf (sid_buf + p, sid_buf_len, "-%lu",
Packit Service d2400d
		               (unsigned long) sub_auths[c]);
Packit Service d2400d
		if (nc < 0 || nc >= sid_buf_len) {
Packit Service d2400d
			free (sid_buf);
Packit Service d2400d
			return NULL;
Packit Service d2400d
		}
Packit Service d2400d
	}
Packit Service d2400d
Packit Service d2400d
	return sid_buf;
Packit Service d2400d
}
Packit Service d2400d
Packit Service d2400d
char *
Packit 8586cb
_adcli_str_dupn (void *data,
Packit 8586cb
                 size_t len)
Packit 8586cb
{
Packit 8586cb
	char *result;
Packit 8586cb
Packit 8586cb
	result = malloc (len + 1);
Packit 8586cb
	return_val_if_fail (result, NULL);
Packit 8586cb
Packit 8586cb
	memcpy (result, data, len);
Packit 8586cb
	result[len] = '\0';
Packit 8586cb
	return result;
Packit 8586cb
}
Packit 8586cb
Packit 8586cb
int
Packit 8586cb
_adcli_str_has_prefix (const char *str,
Packit 8586cb
                       const char *prefix)
Packit 8586cb
{
Packit 8586cb
	size_t len = strlen (str);
Packit 8586cb
	size_t lp = strlen (prefix);
Packit 8586cb
	return (len >= lp && strncmp (str, prefix, lp) == 0);
Packit 8586cb
}
Packit 8586cb
Packit 8586cb
int
Packit 8586cb
_adcli_str_has_suffix (const char *str,
Packit 8586cb
                       const char *suffix)
Packit 8586cb
{
Packit 8586cb
	size_t len = strlen (str);
Packit 8586cb
	size_t ls = strlen (suffix);
Packit 8586cb
	return (len >= ls && strncmp (str + (len - ls), suffix, ls) == 0);
Packit 8586cb
}
Packit 8586cb
Packit 8586cb
int
Packit 8586cb
_adcli_password_free (char *password)
Packit 8586cb
{
Packit 8586cb
	int ret;
Packit 8586cb
Packit 8586cb
	if (password == NULL)
Packit 8586cb
		return 0;
Packit 8586cb
Packit 8586cb
	ret = adcli_mem_clear (password, strlen (password));
Packit 8586cb
	free (password);
Packit 8586cb
	return ret;
Packit 8586cb
}
Packit 8586cb
Packit 8586cb
int
Packit 8586cb
adcli_mem_clear (void *data,
Packit 8586cb
                 size_t length)
Packit 8586cb
{
Packit 8586cb
	volatile char *vp;
Packit 8586cb
	int ret = 0;
Packit 8586cb
Packit 8586cb
	if (data == NULL)
Packit 8586cb
		return 0;
Packit 8586cb
Packit 8586cb
	/*
Packit 8586cb
	 * Cracktastic stuff here to help compilers not
Packit 8586cb
	 * optimize this away
Packit 8586cb
	 */
Packit 8586cb
Packit 8586cb
	vp = (volatile char*)data;
Packit 8586cb
	while (length) {
Packit 8586cb
		*vp = 0xAA;
Packit 8586cb
		ret += *vp;
Packit 8586cb
		vp++;
Packit 8586cb
		length--;
Packit 8586cb
	}
Packit 8586cb
Packit 8586cb
	return ret;
Packit 8586cb
}
Packit 8586cb
Packit 8586cb
int
Packit 8586cb
_adcli_write_all (int fd,
Packit 8586cb
                  const char *buf,
Packit 8586cb
                  int len)
Packit 8586cb
{
Packit 8586cb
	int res;
Packit 8586cb
Packit 8586cb
	if (len == -1)
Packit 8586cb
		len = strlen (buf);
Packit 8586cb
Packit 8586cb
	while (len > 0) {
Packit 8586cb
		res = write (fd, buf, len);
Packit 8586cb
		if (res <= 0) {
Packit 8586cb
			if (errno == EAGAIN || errno == EINTR)
Packit 8586cb
				continue;
Packit 8586cb
			return -errno;
Packit 8586cb
		} else  {
Packit 8586cb
			len -= res;
Packit 8586cb
			buf += res;
Packit 8586cb
		}
Packit 8586cb
	}
Packit 8586cb
Packit 8586cb
	return 0;
Packit 8586cb
}
Packit 8586cb
Packit 8586cb
#define AD_TO_UNIX_TIME_CONST 11644473600LL
Packit 8586cb
Packit 8586cb
bool
Packit 8586cb
_adcli_check_nt_time_string_lifetime (const char *nt_time_string,
Packit 8586cb
                                      unsigned int lifetime)
Packit 8586cb
{
Packit 8586cb
	uint64_t nt_now;
Packit 8586cb
	unsigned long long int pwd_last_set;
Packit 8586cb
	char *endptr;
Packit 8586cb
	time_t now;
Packit 8586cb
Packit 8586cb
	if (nt_time_string == NULL) {
Packit 8586cb
		_adcli_err ("Missing NT time string, assuming it is expired");
Packit 8586cb
		return false;
Packit 8586cb
	}
Packit 8586cb
Packit 8586cb
	if (lifetime == 0) {
Packit 8586cb
		_adcli_info ("Password lifetime is 0, forcing renewal");
Packit 8586cb
		return false;
Packit 8586cb
	}
Packit 8586cb
Packit 8586cb
	now = time (NULL);
Packit 8586cb
	/* NT timestamps start at 1601-01-01 and use a 100ns base */
Packit 8586cb
	nt_now = (now + AD_TO_UNIX_TIME_CONST) * 1000 * 1000 * 10;
Packit 8586cb
	errno = 0;
Packit 8586cb
	pwd_last_set = strtoull (nt_time_string, &endptr, 10);
Packit 8586cb
	if (errno != 0 || *endptr != '\0' || endptr == nt_time_string) {
Packit 8586cb
		_adcli_err ("Failed to convert NT time string, assuming it is expired");
Packit 8586cb
		return false;
Packit 8586cb
	}
Packit 8586cb
Packit 8586cb
	if (pwd_last_set + (lifetime * 24ULL * 60 * 60 \
Packit 8586cb
				* 1000 * 1000 * 10) > nt_now) {
Packit 8586cb
		_adcli_info ("Password not too old, no change needed");
Packit 8586cb
		return true;
Packit 8586cb
	}
Packit 8586cb
Packit 8586cb
	return false;
Packit 8586cb
}
Packit 8586cb
Packit Service cb5865
adcli_result
Packit Service cb5865
_adcli_call_external_program (const char *binary, char * const *argv,
Packit Service cb5865
                              const char *stdin_data,
Packit Service cb5865
                              uint8_t **stdout_data, size_t *stdout_data_len)
Packit Service cb5865
{
Packit Service cb5865
	int ret;
Packit Service cb5865
	int pipefd_to_child[2] = { -1, -1};
Packit Service cb5865
	int pipefd_from_child[2] = { -1, -1};
Packit Service cb5865
	pid_t child_pid = 0;
Packit Service cb5865
	int err;
Packit Service cb5865
	size_t len;
Packit Service cb5865
	ssize_t rlen;
Packit Service cb5865
	pid_t wret;
Packit Service cb5865
	int status;
Packit Service cb5865
	uint8_t read_buf[4096];
Packit Service cb5865
	uint8_t *out;
Packit Service cb5865
Packit Service cb5865
	errno = 0;
Packit Service cb5865
	ret = access (binary, X_OK);
Packit Service cb5865
	if (ret != 0) {
Packit Service cb5865
		err = errno;
Packit Service cb5865
		_adcli_err ("Cannot run [%s]: [%d][%s].", binary, err,
Packit Service cb5865
		                                          strerror (err));
Packit Service cb5865
		ret = ADCLI_ERR_FAIL;
Packit Service cb5865
		goto done;
Packit Service cb5865
	}
Packit Service cb5865
Packit Service cb5865
	ret = pipe (pipefd_from_child);
Packit Service cb5865
	if (ret == -1) {
Packit Service cb5865
		err = errno;
Packit Service cb5865
		_adcli_err ("pipe failed [%d][%s].", err, strerror (err));
Packit Service cb5865
		ret = ADCLI_ERR_FAIL;
Packit Service cb5865
		goto done;
Packit Service cb5865
	}
Packit Service cb5865
Packit Service cb5865
	ret = pipe (pipefd_to_child);
Packit Service cb5865
	if (ret == -1) {
Packit Service cb5865
		err = errno;
Packit Service cb5865
		_adcli_err ("pipe failed [%d][%s].", err, strerror (err));
Packit Service cb5865
		ret = ADCLI_ERR_FAIL;
Packit Service cb5865
		goto done;
Packit Service cb5865
	}
Packit Service cb5865
Packit Service cb5865
	child_pid = fork ();
Packit Service cb5865
Packit Service cb5865
	if (child_pid == 0) { /* child */
Packit Service cb5865
		close (pipefd_to_child[1]);
Packit Service cb5865
		ret = dup2 (pipefd_to_child[0], STDIN_FILENO);
Packit Service cb5865
		if (ret == -1) {
Packit Service cb5865
			err = errno;
Packit Service cb5865
			_adcli_err ("dup2 failed [%d][%s].", err,
Packit Service cb5865
			                                     strerror (err));
Packit Service cb5865
			exit (EXIT_FAILURE);
Packit Service cb5865
		}
Packit Service cb5865
Packit Service cb5865
		close (pipefd_from_child[0]);
Packit Service cb5865
		ret = dup2 (pipefd_from_child[1], STDOUT_FILENO);
Packit Service cb5865
		if (ret == -1) {
Packit Service cb5865
			err = errno;
Packit Service cb5865
			_adcli_err ("dup2 failed [%d][%s].", err,
Packit Service cb5865
			                                     strerror (err));
Packit Service cb5865
			exit (EXIT_FAILURE);
Packit Service cb5865
		}
Packit Service cb5865
Packit Service cb5865
		execv (binary, argv);
Packit Service cb5865
		_adcli_err ("Failed to run %s.", binary);
Packit Service cb5865
		ret = ADCLI_ERR_FAIL;
Packit Service cb5865
		goto done;
Packit Service cb5865
	} else if (child_pid > 0) { /* parent */
Packit Service cb5865
Packit Service cb5865
		if (stdin_data != NULL) {
Packit Service cb5865
			len = strlen (stdin_data);
Packit Service cb5865
			ret = write (pipefd_to_child[1], stdin_data, len);
Packit Service cb5865
			if (ret != len) {
Packit Service cb5865
				_adcli_err ("Failed to send computer account password "
Packit Service cb5865
				            "to net command.");
Packit Service cb5865
				ret = ADCLI_ERR_FAIL;
Packit Service cb5865
				goto done;
Packit Service cb5865
			}
Packit Service cb5865
		}
Packit Service cb5865
Packit Service cb5865
		close (pipefd_to_child[0]);
Packit Service cb5865
		pipefd_to_child[0] = -1;
Packit Service cb5865
		close (pipefd_to_child[1]);
Packit Service cb5865
		pipefd_to_child[0] = -1;
Packit Service cb5865
Packit Service cb5865
		if (stdout_data != NULL || stdout_data_len != NULL) {
Packit Service cb5865
			rlen = read (pipefd_from_child[0], read_buf, sizeof (read_buf));
Packit Service cb5865
			if (rlen < 0) {
Packit Service cb5865
				ret = errno;
Packit Service cb5865
				_adcli_err ("Failed to read from child [%d][%s].\n",
Packit Service cb5865
				            ret, strerror (ret));
Packit Service cb5865
				ret = ADCLI_ERR_FAIL;
Packit Service cb5865
				goto done;
Packit Service cb5865
			}
Packit Service cb5865
Packit Service cb5865
			out = malloc (sizeof(uint8_t) * rlen);
Packit Service cb5865
			if (out == NULL) {
Packit Service cb5865
				_adcli_err ("Failed to allocate memory "
Packit Service cb5865
				            "for child output.");
Packit Service cb5865
				ret = ADCLI_ERR_FAIL;
Packit Service cb5865
				goto done;
Packit Service cb5865
			} else {
Packit Service cb5865
				memcpy (out, read_buf, rlen);
Packit Service cb5865
			}
Packit Service cb5865
Packit Service cb5865
			if (stdout_data != NULL) {
Packit Service cb5865
				*stdout_data = out;
Packit Service cb5865
			} else {
Packit Service cb5865
				free (out);
Packit Service cb5865
			}
Packit Service cb5865
Packit Service cb5865
			if (stdout_data_len != NULL) {
Packit Service cb5865
				*stdout_data_len = rlen;
Packit Service cb5865
			}
Packit Service cb5865
		}
Packit Service cb5865
Packit Service cb5865
	} else {
Packit Service cb5865
		_adcli_err ("Cannot run net command.");
Packit Service cb5865
		ret = ADCLI_ERR_FAIL;
Packit Service cb5865
		goto done;
Packit Service cb5865
	}
Packit Service cb5865
Packit Service cb5865
	ret = ADCLI_SUCCESS;
Packit Service cb5865
Packit Service cb5865
done:
Packit Service cb5865
	if (pipefd_from_child[0] != -1) {
Packit Service cb5865
		close (pipefd_from_child[0]);
Packit Service cb5865
	}
Packit Service cb5865
	if (pipefd_from_child[1] != -1) {
Packit Service cb5865
		close (pipefd_from_child[1]);
Packit Service cb5865
	}
Packit Service cb5865
	if (pipefd_to_child[0] != -1) {
Packit Service cb5865
		close (pipefd_to_child[0]);
Packit Service cb5865
	}
Packit Service cb5865
	if (pipefd_to_child[1] != -1) {
Packit Service cb5865
		close (pipefd_to_child[1]);
Packit Service cb5865
	}
Packit Service cb5865
Packit Service cb5865
	if (child_pid > 0) {
Packit Service cb5865
		wret = waitpid (child_pid, &status, 0);
Packit Service cb5865
		if (wret == -1) {
Packit Service cb5865
			_adcli_err ("No sure what happend to net command.");
Packit Service cb5865
		} else {
Packit Service 74615e
			if (WIFEXITED (status) && WEXITSTATUS (status) != 0) {
Packit Service cb5865
				_adcli_err ("net command failed with %d.",
Packit Service cb5865
				            WEXITSTATUS (status));
Packit Service cb5865
			}
Packit Service cb5865
		}
Packit Service cb5865
	}
Packit Service cb5865
Packit Service cb5865
	return ret;
Packit Service cb5865
}
Packit Service cb5865
Packit Service cb5865
Packit 8586cb
#ifdef UTIL_TESTS
Packit 8586cb
Packit 8586cb
#include "test.h"
Packit 8586cb
Packit 8586cb
static void
Packit 8586cb
test_strv_add_free (void)
Packit 8586cb
{
Packit 8586cb
	char **strv = NULL;
Packit 8586cb
Packit 8586cb
	strv = _adcli_strv_add (strv, strdup ("one"), NULL);
Packit 8586cb
	strv = _adcli_strv_add (strv, strdup ("two"), NULL);
Packit 8586cb
	strv = _adcli_strv_add (strv, strdup ("three"), NULL);
Packit 8586cb
Packit 8586cb
	assert_str_eq (strv[0], "one");
Packit 8586cb
	assert_str_eq (strv[1], "two");
Packit 8586cb
	assert_str_eq (strv[2], "three");
Packit 8586cb
	assert (strv[3] == NULL);
Packit 8586cb
Packit 8586cb
	_adcli_strv_free (strv);
Packit 8586cb
}
Packit 8586cb
Packit 8586cb
static void
Packit Service 09c7c8
test_strv_add_unique_free (void)
Packit Service 09c7c8
{
Packit Service 09c7c8
	char **strv = NULL;
Packit Service 09c7c8
Packit Service 09c7c8
	strv = _adcli_strv_add_unique (strv, strdup ("one"), NULL, false);
Packit Service 09c7c8
	strv = _adcli_strv_add_unique (strv, strdup ("one"), NULL, false);
Packit Service 09c7c8
	strv = _adcli_strv_add_unique (strv, strdup ("two"), NULL, false);
Packit Service 09c7c8
	strv = _adcli_strv_add_unique (strv, strdup ("two"), NULL, false);
Packit Service 09c7c8
	strv = _adcli_strv_add_unique (strv, strdup ("tWo"), NULL, false);
Packit Service 09c7c8
	strv = _adcli_strv_add_unique (strv, strdup ("three"), NULL, false);
Packit Service 09c7c8
	strv = _adcli_strv_add_unique (strv, strdup ("three"), NULL, false);
Packit Service 09c7c8
	strv = _adcli_strv_add_unique (strv, strdup ("TWO"), NULL, true);
Packit Service 09c7c8
Packit Service 09c7c8
	assert_num_eq (_adcli_strv_len (strv), 4);
Packit Service 09c7c8
Packit Service 09c7c8
	assert_str_eq (strv[0], "one");
Packit Service 09c7c8
	assert_str_eq (strv[1], "two");
Packit Service 09c7c8
	assert_str_eq (strv[2], "three");
Packit Service 09c7c8
	assert_str_eq (strv[3], "TWO");
Packit Service 09c7c8
	assert (strv[4] == NULL);
Packit Service 09c7c8
Packit Service 09c7c8
	_adcli_strv_free (strv);
Packit Service 09c7c8
}
Packit Service 09c7c8
Packit Service 09c7c8
Packit Service 09c7c8
static void
Packit 8586cb
test_strv_dup (void)
Packit 8586cb
{
Packit 8586cb
	char *values[] = { "one", "two", "three", NULL };
Packit 8586cb
	char **strv;
Packit 8586cb
Packit 8586cb
	strv = _adcli_strv_dup (values);
Packit 8586cb
Packit 8586cb
	assert_str_eq (strv[0], "one");
Packit 8586cb
	assert_str_eq (strv[1], "two");
Packit 8586cb
	assert_str_eq (strv[2], "three");
Packit 8586cb
	assert (strv[3] == NULL);
Packit 8586cb
Packit 8586cb
	_adcli_strv_free (strv);
Packit 8586cb
}
Packit 8586cb
Packit 8586cb
static void
Packit 8586cb
test_strv_count (void)
Packit 8586cb
{
Packit 8586cb
	char *values[] = { "one", "two", "three", NULL };
Packit 8586cb
	int len;
Packit 8586cb
Packit 8586cb
	len = _adcli_strv_len (values);
Packit 8586cb
	assert_num_eq (len, 3);
Packit 8586cb
}
Packit 8586cb
Packit 8586cb
static void
Packit 8586cb
test_check_nt_time_string_lifetime (void)
Packit 8586cb
{
Packit 8586cb
	char *time_str;
Packit 8586cb
Packit 8586cb
	/* Missing or invalid value */
Packit 8586cb
	assert (!_adcli_check_nt_time_string_lifetime (NULL, 0));
Packit 8586cb
	assert (!_adcli_check_nt_time_string_lifetime ("", 0));
Packit 8586cb
	assert (!_adcli_check_nt_time_string_lifetime ("a", 0));
Packit 8586cb
	assert (!_adcli_check_nt_time_string_lifetime ("1a", 0));
Packit 8586cb
Packit 8586cb
	/* Certainly expired*/
Packit 8586cb
	assert (!_adcli_check_nt_time_string_lifetime ("0", 0));
Packit 8586cb
Packit 8586cb
	/* 1969-01-01T00:00:00: 116129340000000000 */
Packit 8586cb
	/* Calculated with PowerShell:
Packit 8586cb
	 * (Get-Date -Date "1969-01-01T00:00:00").ToFileTime() */
Packit 8586cb
Packit 8586cb
	assert (!_adcli_check_nt_time_string_lifetime ("130645404000000000", 1));
Packit 8586cb
Packit 8586cb
	/* Make sure lifetime==0 will retrun false even if pwdLastSet is in the future */
Packit 8586cb
	assert (asprintf (&time_str, "%llu",
Packit 8586cb
			  (time (NULL) + 10 + AD_TO_UNIX_TIME_CONST) * 1000 * 1000 *10)
Packit 8586cb
		!= -1);
Packit 8586cb
	assert (!_adcli_check_nt_time_string_lifetime (time_str, 0));
Packit Service 29d2be
	free (time_str);
Packit 8586cb
Packit 8586cb
	/* This test will fail some time after 2200AD as a reminder to reflect
Packit 8586cb
	 * why adcli is still needed. */
Packit 8586cb
	assert (_adcli_check_nt_time_string_lifetime ("130645404000000000", 100000));
Packit 8586cb
}
Packit 8586cb
Packit Service d2400d
static void
Packit Service d2400d
test_bin_sid_to_str (void)
Packit Service d2400d
{
Packit Service d2400d
	uint8_t sid1[] = { 0x01, 0x05, 0x00, 0x00, 0x00, 0x00, 0x00, 0x05,
Packit Service d2400d
	                   0x15, 0x00, 0x00, 0x00, 0xF8, 0x12, 0x13, 0xDC,
Packit Service d2400d
	                   0x47, 0xF3, 0x1C, 0x76, 0x47, 0x2F, 0x2E, 0xD7,
Packit Service d2400d
	                   0x51, 0x04, 0x00, 0x00 };
Packit Service d2400d
Packit Service d2400d
	uint8_t sid2[] = { 0x01, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x05,
Packit Service d2400d
	                   0x15, 0x00, 0x00, 0x00, 0xF8, 0x12, 0x13, 0xDC,
Packit Service d2400d
	                   0x47, 0xF3, 0x1C, 0x76, 0x47, 0x2F, 0x2E, 0xD7};
Packit Service d2400d
Packit Service d2400d
	uint8_t sid3[] = { 0x01, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x05,
Packit Service d2400d
	                   0x15, 0x00, 0x00, 0x00, 0x29, 0xC9, 0x4F, 0xD9,
Packit Service d2400d
	                   0xC2, 0x3C, 0xC3, 0x78, 0x36, 0x55, 0x87, 0xF8};
Packit Service d2400d
Packit Service d2400d
Packit Service d2400d
	char *str;
Packit Service d2400d
Packit Service d2400d
	str = _adcli_bin_sid_to_str (sid1, sizeof (sid1));
Packit Service d2400d
	assert (str != NULL);
Packit Service d2400d
	assert (strcmp (str, "S-1-5-21-3692237560-1981608775-3610128199-1105") == 0);
Packit Service d2400d
	free (str);
Packit Service d2400d
Packit Service d2400d
	str = _adcli_bin_sid_to_str (sid2, sizeof (sid2));
Packit Service d2400d
	assert (str != NULL);
Packit Service d2400d
	assert (strcmp (str, "S-1-5-21-3692237560-1981608775-3610128199") == 0);
Packit Service d2400d
	free (str);
Packit Service d2400d
Packit Service d2400d
	str = _adcli_bin_sid_to_str (sid3, sizeof (sid2));
Packit Service d2400d
	assert (str != NULL);
Packit Service d2400d
	assert (strcmp (str, "S-1-5-21-3645884713-2026060994-4169618742") == 0);
Packit Service d2400d
	free (str);
Packit Service d2400d
}
Packit Service d2400d
Packit Service cb5865
static void
Packit Service cb5865
test_call_external_program (void)
Packit Service cb5865
{
Packit Service cb5865
	adcli_result res;
Packit Service cb5865
	char *argv[] = { NULL, NULL, NULL };
Packit Service cb5865
	uint8_t *stdout_data;
Packit Service cb5865
	size_t stdout_data_len;
Packit Service cb5865
Packit Service cb5865
	argv[0] = "/does/not/exists";
Packit Service cb5865
	res = _adcli_call_external_program (argv[0], argv, NULL, NULL, NULL);
Packit Service cb5865
	assert (res == ADCLI_ERR_FAIL);
Packit Service cb5865
Packit Service cb5865
#ifdef BIN_CAT
Packit Service cb5865
	argv[0] = BIN_CAT;
Packit Service cb5865
	res = _adcli_call_external_program (argv[0], argv, "Hello",
Packit Service cb5865
	                                    &stdout_data, &stdout_data_len);
Packit Service cb5865
	assert (res == ADCLI_SUCCESS);
Packit Service cb5865
	assert (strncmp ("Hello", (char *) stdout_data, stdout_data_len) == 0);
Packit Service cb5865
	free (stdout_data);
Packit Service cb5865
Packit Service cb5865
	res = _adcli_call_external_program (argv[0], argv, "Hello",
Packit Service cb5865
	                                    NULL, NULL);
Packit Service cb5865
	assert (res == ADCLI_SUCCESS);
Packit Service cb5865
#endif
Packit Service cb5865
Packit Service cb5865
#ifdef BIN_REV
Packit Service cb5865
	argv[0] = BIN_REV;
Packit Service cb5865
	res = _adcli_call_external_program (argv[0], argv, "Hello\n",
Packit Service cb5865
	                                    &stdout_data, &stdout_data_len);
Packit Service cb5865
	assert (res == ADCLI_SUCCESS);
Packit Service cb5865
	assert (strncmp ("olleH\n", (char *) stdout_data, stdout_data_len) == 0);
Packit Service cb5865
	free (stdout_data);
Packit Service cb5865
#endif
Packit Service cb5865
Packit Service cb5865
#ifdef BIN_TAC
Packit Service cb5865
	argv[0] = BIN_TAC;
Packit Service cb5865
	res = _adcli_call_external_program (argv[0], argv, "Hello\nWorld\n",
Packit Service cb5865
	                                    &stdout_data, &stdout_data_len);
Packit Service cb5865
	assert (res == ADCLI_SUCCESS);
Packit Service cb5865
	assert (strncmp ("World\nHello\n", (char *) stdout_data, stdout_data_len) == 0);
Packit Service cb5865
	free (stdout_data);
Packit Service cb5865
#endif
Packit Service cb5865
Packit Service cb5865
#ifdef BIN_ECHO
Packit Service cb5865
	argv[0] = BIN_ECHO;
Packit Service cb5865
	argv[1] = "Hello";
Packit Service cb5865
	res = _adcli_call_external_program (argv[0], argv, NULL,
Packit Service cb5865
	                                    &stdout_data, &stdout_data_len);
Packit Service cb5865
	assert (res == ADCLI_SUCCESS);
Packit Service cb5865
	assert (strncmp ("Hello\n", (char *) stdout_data, stdout_data_len) == 0);
Packit Service cb5865
	free (stdout_data);
Packit Service cb5865
#endif
Packit Service cb5865
}
Packit Service cb5865
Packit 8586cb
int
Packit 8586cb
main (int argc,
Packit 8586cb
      char *argv[])
Packit 8586cb
{
Packit 8586cb
	test_func (test_strv_add_free, "/util/strv_add_free");
Packit Service 09c7c8
	test_func (test_strv_add_unique_free, "/util/strv_add_unique_free");
Packit 8586cb
	test_func (test_strv_dup, "/util/strv_dup");
Packit 8586cb
	test_func (test_strv_count, "/util/strv_count");
Packit 8586cb
	test_func (test_check_nt_time_string_lifetime, "/util/check_nt_time_string_lifetime");
Packit Service d2400d
	test_func (test_bin_sid_to_str, "/util/bin_sid_to_str");
Packit Service cb5865
	test_func (test_call_external_program, "/util/call_external_program");
Packit 8586cb
	return test_run (argc, argv);
Packit 8586cb
}
Packit 8586cb
Packit 8586cb
#endif /* UTIL_TESTS */