Add NetUserAdd to libnetapi.
authorGünther Deschner <gd@samba.org>
Wed, 9 Apr 2008 10:38:22 +0000 (12:38 +0200)
committerGünther Deschner <gd@samba.org>
Wed, 9 Apr 2008 11:23:09 +0000 (13:23 +0200)
Guenther
(This used to be commit cb98996ed2ac93a0e15838048405772d2043021a)

source3/Makefile.in
source3/lib/netapi/libnetapi.c
source3/lib/netapi/libnetapi.h
source3/lib/netapi/netapi.h
source3/lib/netapi/user.c [new file with mode: 0644]

index cc45acd8a8df5b9cce880338cb73c389e4f7c820..781e8de41617ae62c382f8f7eb8beb40cba8fb88 100644 (file)
@@ -818,7 +818,8 @@ LIBNETAPI_OBJ1 = lib/netapi/netapi.o \
                 lib/netapi/libnetapi.o \
                 lib/netapi/joindomain.o \
                 lib/netapi/serverinfo.o \
-                lib/netapi/getdc.o
+                lib/netapi/getdc.o \
+                lib/netapi/user.o
 
 LIBNETAPI_OBJ  = $(LIBNETAPI_OBJ1) $(LIBNET_OBJ) \
                 $(LIBSMBCONF_OBJ) \
index ed97df21439de804172b837fc96cf33086d4b2c0..9d92dac39f169b9729ae86167f49c115093326af 100644 (file)
@@ -441,3 +441,49 @@ NET_API_STATUS DsGetDcName(const char * server_name /* [in] [unique] */,
        return r.out.result;
 }
 
+/****************************************************************
+ NetUserAdd
+****************************************************************/
+
+NET_API_STATUS NetUserAdd(const char * server_name /* [in] [unique] */,
+                         uint32_t level /* [in] */,
+                         uint8_t *buffer /* [in] [ref] */,
+                         uint32_t *parm_error /* [out] [ref] */)
+{
+       struct NetUserAdd r;
+       struct libnetapi_ctx *ctx = NULL;
+       NET_API_STATUS status;
+       WERROR werr;
+
+       status = libnetapi_getctx(&ctx);
+       if (status != 0) {
+               return status;
+       }
+
+       /* In parameters */
+       r.in.server_name = server_name;
+       r.in.level = level;
+       r.in.buffer = buffer;
+
+       /* Out parameters */
+       r.out.parm_error = parm_error;
+
+       if (DEBUGLEVEL >= 10) {
+               NDR_PRINT_IN_DEBUG(NetUserAdd, &r);
+       }
+
+       if (LIBNETAPI_LOCAL_SERVER(server_name)) {
+               werr = NetUserAdd_l(ctx, &r);
+       } else {
+               werr = NetUserAdd_r(ctx, &r);
+       }
+
+       r.out.result = W_ERROR_V(werr);
+
+       if (DEBUGLEVEL >= 10) {
+               NDR_PRINT_OUT_DEBUG(NetUserAdd, &r);
+       }
+
+       return r.out.result;
+}
+
index 99c5295c56835c6a975c6de0d0328240de8bb6a6..8e4e73bcd85409ca39c1e3a1120927444134ab52 100644 (file)
@@ -74,4 +74,12 @@ WERROR DsGetDcName_r(struct libnetapi_ctx *ctx,
                     struct DsGetDcName *r);
 WERROR DsGetDcName_l(struct libnetapi_ctx *ctx,
                     struct DsGetDcName *r);
+NET_API_STATUS NetUserAdd(const char * server_name /* [in] [unique] */,
+                         uint32_t level /* [in] */,
+                         uint8_t *buffer /* [in] [ref] */,
+                         uint32_t *parm_error /* [out] [ref] */);
+WERROR NetUserAdd_r(struct libnetapi_ctx *ctx,
+                   struct NetUserAdd *r);
+WERROR NetUserAdd_l(struct libnetapi_ctx *ctx,
+                   struct NetUserAdd *r);
 #endif /* __LIBNETAPI_LIBNETAPI__ */
index 68f23720ff2c6bef31050a4bdde3cfe3bee12bb0..f328f5794648c1a58d9bd9934a850f770847a743 100644 (file)
@@ -57,6 +57,21 @@ struct DOMAIN_CONTROLLER_INFO {
        const char * client_site_name;
 };
 
+struct USER_INFO_0 {
+       const char * usri0_name;
+};
+
+struct USER_INFO_1 {
+       const char * usri1_name;
+       const char * usri1_password;
+       uint32_t usri1_password_age;
+       uint32_t usri1_priv;
+       const char * usri1_home_dir;
+       const char * usri1_comment;
+       uint32_t usri1_flags;
+       const char * usri1_script_path;
+};
+
 #endif /* _HEADER_libnetapi */
 
 /****************************************************************
@@ -176,4 +191,13 @@ NET_API_STATUS DsGetDcName(const char * server_name /* [in] [unique] */,
                           const char * site_name /* [in] [unique] */,
                           uint32_t flags /* [in] */,
                           struct DOMAIN_CONTROLLER_INFO **dc_info /* [out] [ref] */);
+
+/****************************************************************
+ NetUserAdd
+****************************************************************/
+
+NET_API_STATUS NetUserAdd(const char * server_name /* [in] */,
+                         uint32_t level /* [in] */,
+                         uint8_t *buffer /* [in] [ref] */,
+                         uint32_t *parm_error /* [out] [ref] */);
 #endif
diff --git a/source3/lib/netapi/user.c b/source3/lib/netapi/user.c
new file mode 100644 (file)
index 0000000..71f08c2
--- /dev/null
@@ -0,0 +1,358 @@
+/*
+ *  Unix SMB/CIFS implementation.
+ *  NetApi User Support
+ *  Copyright (C) Guenther Deschner 2008
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 3 of the License, or
+ *  (at your option) any later version.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; if not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include "includes.h"
+
+#include "librpc/gen_ndr/libnetapi.h"
+#include "lib/netapi/netapi.h"
+#include "lib/netapi/libnetapi.h"
+
+/****************************************************************
+****************************************************************/
+
+WERROR NetUserAdd_l(struct libnetapi_ctx *ctx,
+                   struct NetUserAdd *r)
+{
+       return WERR_NOT_SUPPORTED;
+}
+
+/****************************************************************
+****************************************************************/
+
+static void convert_USER_INFO_1_to_samr_user_info25(struct USER_INFO_1 *info1,
+                                                   DATA_BLOB *user_session_key,
+                                                   struct samr_UserInfo25 *info25)
+{
+       uint32_t fields_present = SAMR_FIELD_ACCT_FLAGS;
+       struct samr_LogonHours zero_logon_hours;
+       struct lsa_BinaryString zero_parameters;
+       uint32_t acct_flags = 0;
+       NTTIME password_age;
+
+       ZERO_STRUCTP(info25);
+       ZERO_STRUCT(zero_logon_hours);
+       ZERO_STRUCT(zero_parameters);
+
+       if (info1->usri1_name) {
+               fields_present |= SAMR_FIELD_FULL_NAME;
+       }
+       if (info1->usri1_password) {
+               fields_present |= SAMR_FIELD_PASSWORD;
+       }
+       if (info1->usri1_flags) {
+               fields_present |= SAMR_FIELD_ACCT_FLAGS;
+       }
+       if (info1->usri1_name) {
+               fields_present |= SAMR_FIELD_FULL_NAME;
+       }
+       if (info1->usri1_home_dir) {
+               fields_present |= SAMR_FIELD_HOME_DIRECTORY;
+       }
+       if (info1->usri1_script_path) {
+               fields_present |= SAMR_FIELD_LOGON_SCRIPT;
+       }
+       if (info1->usri1_comment) {
+               fields_present |= SAMR_FIELD_DESCRIPTION;
+       }
+       if (info1->usri1_password_age) {
+               fields_present |= SAMR_FIELD_FORCE_PWD_CHANGE;
+       }
+
+       acct_flags |= info1->usri1_flags | ACB_NORMAL;
+
+       unix_to_nt_time_abs(&password_age, info1->usri1_password_age);
+
+       /* TODO: info1->usri1_priv */
+       init_samr_user_info21(&info25->info,
+                             0,
+                             0,
+                             0,
+                             0,
+                             0,
+                             password_age,
+                             NULL,
+                             info1->usri1_name,
+                             info1->usri1_home_dir,
+                             NULL,
+                             info1->usri1_script_path,
+                             NULL,
+                             info1->usri1_comment,
+                             NULL,
+                             NULL,
+                             &zero_parameters,
+                             0,
+                             0,
+                             acct_flags,
+                             fields_present,
+                             zero_logon_hours,
+                             0,
+                             0,
+                             0,
+                             0,
+                             0,
+                             0,
+                             0);
+
+       if (info1->usri1_password) {
+               uchar pwbuf[532];
+               struct MD5Context ctx;
+               uint8_t confounder[16];
+               DATA_BLOB confounded_session_key = data_blob(NULL, 16);
+
+               encode_pw_buffer(pwbuf, info1->usri1_password, STR_UNICODE);
+
+               generate_random_buffer((uint8_t *)confounder, 16);
+
+               MD5Init(&ctx);
+               MD5Update(&ctx, confounder, 16);
+               MD5Update(&ctx, user_session_key->data,
+                               user_session_key->length);
+               MD5Final(confounded_session_key.data, &ctx);
+
+               SamOEMhashBlob(pwbuf, 516, &confounded_session_key);
+               memcpy(&pwbuf[516], confounder, 16);
+
+               memcpy(info25->password.data, pwbuf, sizeof(pwbuf));
+               data_blob_free(&confounded_session_key);
+       }
+}
+
+/****************************************************************
+****************************************************************/
+
+WERROR NetUserAdd_r(struct libnetapi_ctx *ctx,
+                   struct NetUserAdd *r)
+{
+       struct cli_state *cli = NULL;
+       struct rpc_pipe_client *pipe_cli = NULL;
+       NTSTATUS status;
+       WERROR werr;
+       uint32_t resume_handle = 0;
+       uint32_t num_entries = 0;
+       POLICY_HND connect_handle, domain_handle, user_handle;
+       struct samr_SamArray *sam = NULL;
+       const char *domain_name = NULL;
+       struct lsa_String lsa_domain_name, lsa_account_name;
+       struct dom_sid2 *domain_sid = NULL;
+       struct samr_UserInfo25 info25;
+       union samr_UserInfo *user_info = NULL;
+       struct samr_PwInfo pw_info;
+       uint32_t access_granted = 0;
+       uint32_t rid = 0;
+       bool domain_found = true;
+       int i;
+       struct USER_INFO_1 *info1;
+
+       ZERO_STRUCT(connect_handle);
+       ZERO_STRUCT(domain_handle);
+       ZERO_STRUCT(user_handle);
+
+       if (!r->in.buffer) {
+               return WERR_INVALID_PARAM;
+       }
+
+       switch (r->in.level) {
+               case 1:
+                       info1 = (struct USER_INFO_1 *)r->in.buffer;
+                       break;
+               case 2:
+               case 3:
+               case 4:
+               default:
+                       werr = WERR_NOT_SUPPORTED;
+                       goto done;
+       }
+
+       status = cli_full_connection(&cli, NULL, r->in.server_name,
+                                    NULL, 0,
+                                    "IPC$", "IPC",
+                                    ctx->username,
+                                    ctx->workgroup,
+                                    ctx->password,
+                                    CLI_FULL_CONNECTION_USE_KERBEROS |
+                                    CLI_FULL_CONNECTION_FALLBACK_AFTER_KERBEROS,
+                                    Undefined, NULL);
+
+       if (!NT_STATUS_IS_OK(status)) {
+               werr = ntstatus_to_werror(status);
+               goto done;
+       }
+
+       pipe_cli = cli_rpc_pipe_open_noauth(cli, PI_SAMR, &status);
+       if (!pipe_cli) {
+               werr = ntstatus_to_werror(status);
+               goto done;
+       }
+
+       status = rpccli_try_samr_connects(pipe_cli, ctx,
+                                         SAMR_ACCESS_ENUM_DOMAINS |
+                                         SAMR_ACCESS_OPEN_DOMAIN,
+                                         &connect_handle);
+       if (!NT_STATUS_IS_OK(status)) {
+               werr = ntstatus_to_werror(status);
+               goto done;
+       }
+
+       status = rpccli_samr_EnumDomains(pipe_cli, ctx,
+                                        &connect_handle,
+                                        &resume_handle,
+                                        &sam,
+                                        0xffffffff,
+                                        &num_entries);
+       if (!NT_STATUS_IS_OK(status)) {
+               werr = ntstatus_to_werror(status);
+               goto done;
+       }
+
+       for (i=0; i<num_entries; i++) {
+
+               domain_name = sam->entries[i].name.string;
+
+               if (strequal(domain_name, builtin_domain_name())) {
+                       continue;
+               }
+
+               domain_found = true;
+               break;
+       }
+
+       if (!domain_found) {
+               werr = WERR_NO_SUCH_DOMAIN;
+               goto done;
+       }
+
+       init_lsa_String(&lsa_domain_name, domain_name);
+
+       status = rpccli_samr_LookupDomain(pipe_cli, ctx,
+                                         &connect_handle,
+                                         &lsa_domain_name,
+                                         &domain_sid);
+       if (!NT_STATUS_IS_OK(status)) {
+               werr = ntstatus_to_werror(status);
+               goto done;
+       }
+
+       status = rpccli_samr_OpenDomain(pipe_cli, ctx,
+                                       &connect_handle,
+                                       SAMR_DOMAIN_ACCESS_LOOKUP_INFO_1 |
+                                       SAMR_DOMAIN_ACCESS_CREATE_USER |
+                                       SAMR_DOMAIN_ACCESS_OPEN_ACCOUNT,
+                                       domain_sid,
+                                       &domain_handle);
+       if (!NT_STATUS_IS_OK(status)) {
+               werr = ntstatus_to_werror(status);
+               goto done;
+       }
+
+       init_lsa_String(&lsa_account_name, info1->usri1_name);
+
+       status = rpccli_samr_CreateUser2(pipe_cli, ctx,
+                                        &domain_handle,
+                                        &lsa_account_name,
+                                        ACB_NORMAL,
+                                        SEC_STD_WRITE_DAC |
+                                        SEC_STD_DELETE |
+                                        SAMR_USER_ACCESS_SET_PASSWORD |
+                                        SAMR_USER_ACCESS_SET_ATTRIBUTES |
+                                        SAMR_USER_ACCESS_GET_ATTRIBUTES,
+                                        &user_handle,
+                                        &access_granted,
+                                        &rid);
+       if (!NT_STATUS_IS_OK(status)) {
+               werr = ntstatus_to_werror(status);
+               goto done;
+       }
+
+       status = rpccli_samr_QueryUserInfo(pipe_cli, ctx,
+                                          &user_handle,
+                                          16,
+                                          &user_info);
+       if (!NT_STATUS_IS_OK(status)) {
+               werr = ntstatus_to_werror(status);
+               goto done;
+       }
+
+       if (!(user_info->info16.acct_flags & ACB_NORMAL)) {
+               werr = WERR_INVALID_PARAM;
+               goto done;
+       }
+
+       status = rpccli_samr_GetUserPwInfo(pipe_cli, ctx,
+                                          &user_handle,
+                                          &pw_info);
+       if (!NT_STATUS_IS_OK(status)) {
+               werr = ntstatus_to_werror(status);
+               goto done;
+       }
+
+       ZERO_STRUCTP(user_info);
+
+       convert_USER_INFO_1_to_samr_user_info25(info1,
+                                               &cli->user_session_key,
+                                               &info25);
+
+       if (info1->usri1_password) {
+               user_info->info25 = info25;
+               status = rpccli_samr_SetUserInfo2(pipe_cli, ctx,
+                                                 &user_handle,
+                                                 25,
+                                                 user_info);
+       } else {
+               user_info->info21 = info25.info;
+               status = rpccli_samr_SetUserInfo(pipe_cli, ctx,
+                                                &user_handle,
+                                                21,
+                                                user_info);
+
+       }
+       if (!NT_STATUS_IS_OK(status)) {
+               werr = ntstatus_to_werror(status);
+               goto failed;
+       }
+
+       werr = WERR_OK;
+       goto done;
+
+ failed:
+       status = rpccli_samr_DeleteUser(pipe_cli, ctx,
+                                       &user_handle);
+       if (!NT_STATUS_IS_OK(status)) {
+               werr = ntstatus_to_werror(status);
+               goto done;
+       }
+
+ done:
+       if (!cli) {
+               return werr;
+       }
+
+       if (is_valid_policy_hnd(&user_handle)) {
+               rpccli_samr_Close(pipe_cli, ctx, &user_handle);
+       }
+       if (is_valid_policy_hnd(&domain_handle)) {
+               rpccli_samr_Close(pipe_cli, ctx, &domain_handle);
+       }
+       if (is_valid_policy_hnd(&connect_handle)) {
+               rpccli_samr_Close(pipe_cli, ctx, &connect_handle);
+       }
+
+       cli_shutdown(cli);
+
+       return werr;
+}