Add NetUserAdd to libnetapi.
[kai/samba.git] / source3 / lib / netapi / user.c
1 /*
2  *  Unix SMB/CIFS implementation.
3  *  NetApi User Support
4  *  Copyright (C) Guenther Deschner 2008
5  *
6  *  This program is free software; you can redistribute it and/or modify
7  *  it under the terms of the GNU General Public License as published by
8  *  the Free Software Foundation; either version 3 of the License, or
9  *  (at your option) any later version.
10  *
11  *  This program is distributed in the hope that it will be useful,
12  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
13  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14  *  GNU General Public License for more details.
15  *
16  *  You should have received a copy of the GNU General Public License
17  *  along with this program; if not, see <http://www.gnu.org/licenses/>.
18  */
19
20 #include "includes.h"
21
22 #include "librpc/gen_ndr/libnetapi.h"
23 #include "lib/netapi/netapi.h"
24 #include "lib/netapi/libnetapi.h"
25
26 /****************************************************************
27 ****************************************************************/
28
29 WERROR NetUserAdd_l(struct libnetapi_ctx *ctx,
30                     struct NetUserAdd *r)
31 {
32         return WERR_NOT_SUPPORTED;
33 }
34
35 /****************************************************************
36 ****************************************************************/
37
38 static void convert_USER_INFO_1_to_samr_user_info25(struct USER_INFO_1 *info1,
39                                                     DATA_BLOB *user_session_key,
40                                                     struct samr_UserInfo25 *info25)
41 {
42         uint32_t fields_present = SAMR_FIELD_ACCT_FLAGS;
43         struct samr_LogonHours zero_logon_hours;
44         struct lsa_BinaryString zero_parameters;
45         uint32_t acct_flags = 0;
46         NTTIME password_age;
47
48         ZERO_STRUCTP(info25);
49         ZERO_STRUCT(zero_logon_hours);
50         ZERO_STRUCT(zero_parameters);
51
52         if (info1->usri1_name) {
53                 fields_present |= SAMR_FIELD_FULL_NAME;
54         }
55         if (info1->usri1_password) {
56                 fields_present |= SAMR_FIELD_PASSWORD;
57         }
58         if (info1->usri1_flags) {
59                 fields_present |= SAMR_FIELD_ACCT_FLAGS;
60         }
61         if (info1->usri1_name) {
62                 fields_present |= SAMR_FIELD_FULL_NAME;
63         }
64         if (info1->usri1_home_dir) {
65                 fields_present |= SAMR_FIELD_HOME_DIRECTORY;
66         }
67         if (info1->usri1_script_path) {
68                 fields_present |= SAMR_FIELD_LOGON_SCRIPT;
69         }
70         if (info1->usri1_comment) {
71                 fields_present |= SAMR_FIELD_DESCRIPTION;
72         }
73         if (info1->usri1_password_age) {
74                 fields_present |= SAMR_FIELD_FORCE_PWD_CHANGE;
75         }
76
77         acct_flags |= info1->usri1_flags | ACB_NORMAL;
78
79         unix_to_nt_time_abs(&password_age, info1->usri1_password_age);
80
81         /* TODO: info1->usri1_priv */
82         init_samr_user_info21(&info25->info,
83                               0,
84                               0,
85                               0,
86                               0,
87                               0,
88                               password_age,
89                               NULL,
90                               info1->usri1_name,
91                               info1->usri1_home_dir,
92                               NULL,
93                               info1->usri1_script_path,
94                               NULL,
95                               info1->usri1_comment,
96                               NULL,
97                               NULL,
98                               &zero_parameters,
99                               0,
100                               0,
101                               acct_flags,
102                               fields_present,
103                               zero_logon_hours,
104                               0,
105                               0,
106                               0,
107                               0,
108                               0,
109                               0,
110                               0);
111
112         if (info1->usri1_password) {
113                 uchar pwbuf[532];
114                 struct MD5Context ctx;
115                 uint8_t confounder[16];
116                 DATA_BLOB confounded_session_key = data_blob(NULL, 16);
117
118                 encode_pw_buffer(pwbuf, info1->usri1_password, STR_UNICODE);
119
120                 generate_random_buffer((uint8_t *)confounder, 16);
121
122                 MD5Init(&ctx);
123                 MD5Update(&ctx, confounder, 16);
124                 MD5Update(&ctx, user_session_key->data,
125                                 user_session_key->length);
126                 MD5Final(confounded_session_key.data, &ctx);
127
128                 SamOEMhashBlob(pwbuf, 516, &confounded_session_key);
129                 memcpy(&pwbuf[516], confounder, 16);
130
131                 memcpy(info25->password.data, pwbuf, sizeof(pwbuf));
132                 data_blob_free(&confounded_session_key);
133         }
134 }
135
136 /****************************************************************
137 ****************************************************************/
138
139 WERROR NetUserAdd_r(struct libnetapi_ctx *ctx,
140                     struct NetUserAdd *r)
141 {
142         struct cli_state *cli = NULL;
143         struct rpc_pipe_client *pipe_cli = NULL;
144         NTSTATUS status;
145         WERROR werr;
146         uint32_t resume_handle = 0;
147         uint32_t num_entries = 0;
148         POLICY_HND connect_handle, domain_handle, user_handle;
149         struct samr_SamArray *sam = NULL;
150         const char *domain_name = NULL;
151         struct lsa_String lsa_domain_name, lsa_account_name;
152         struct dom_sid2 *domain_sid = NULL;
153         struct samr_UserInfo25 info25;
154         union samr_UserInfo *user_info = NULL;
155         struct samr_PwInfo pw_info;
156         uint32_t access_granted = 0;
157         uint32_t rid = 0;
158         bool domain_found = true;
159         int i;
160         struct USER_INFO_1 *info1;
161
162         ZERO_STRUCT(connect_handle);
163         ZERO_STRUCT(domain_handle);
164         ZERO_STRUCT(user_handle);
165
166         if (!r->in.buffer) {
167                 return WERR_INVALID_PARAM;
168         }
169
170         switch (r->in.level) {
171                 case 1:
172                         info1 = (struct USER_INFO_1 *)r->in.buffer;
173                         break;
174                 case 2:
175                 case 3:
176                 case 4:
177                 default:
178                         werr = WERR_NOT_SUPPORTED;
179                         goto done;
180         }
181
182         status = cli_full_connection(&cli, NULL, r->in.server_name,
183                                      NULL, 0,
184                                      "IPC$", "IPC",
185                                      ctx->username,
186                                      ctx->workgroup,
187                                      ctx->password,
188                                      CLI_FULL_CONNECTION_USE_KERBEROS |
189                                      CLI_FULL_CONNECTION_FALLBACK_AFTER_KERBEROS,
190                                      Undefined, NULL);
191
192         if (!NT_STATUS_IS_OK(status)) {
193                 werr = ntstatus_to_werror(status);
194                 goto done;
195         }
196
197         pipe_cli = cli_rpc_pipe_open_noauth(cli, PI_SAMR, &status);
198         if (!pipe_cli) {
199                 werr = ntstatus_to_werror(status);
200                 goto done;
201         }
202
203         status = rpccli_try_samr_connects(pipe_cli, ctx,
204                                           SAMR_ACCESS_ENUM_DOMAINS |
205                                           SAMR_ACCESS_OPEN_DOMAIN,
206                                           &connect_handle);
207         if (!NT_STATUS_IS_OK(status)) {
208                 werr = ntstatus_to_werror(status);
209                 goto done;
210         }
211
212         status = rpccli_samr_EnumDomains(pipe_cli, ctx,
213                                          &connect_handle,
214                                          &resume_handle,
215                                          &sam,
216                                          0xffffffff,
217                                          &num_entries);
218         if (!NT_STATUS_IS_OK(status)) {
219                 werr = ntstatus_to_werror(status);
220                 goto done;
221         }
222
223         for (i=0; i<num_entries; i++) {
224
225                 domain_name = sam->entries[i].name.string;
226
227                 if (strequal(domain_name, builtin_domain_name())) {
228                         continue;
229                 }
230
231                 domain_found = true;
232                 break;
233         }
234
235         if (!domain_found) {
236                 werr = WERR_NO_SUCH_DOMAIN;
237                 goto done;
238         }
239
240         init_lsa_String(&lsa_domain_name, domain_name);
241
242         status = rpccli_samr_LookupDomain(pipe_cli, ctx,
243                                           &connect_handle,
244                                           &lsa_domain_name,
245                                           &domain_sid);
246         if (!NT_STATUS_IS_OK(status)) {
247                 werr = ntstatus_to_werror(status);
248                 goto done;
249         }
250
251         status = rpccli_samr_OpenDomain(pipe_cli, ctx,
252                                         &connect_handle,
253                                         SAMR_DOMAIN_ACCESS_LOOKUP_INFO_1 |
254                                         SAMR_DOMAIN_ACCESS_CREATE_USER |
255                                         SAMR_DOMAIN_ACCESS_OPEN_ACCOUNT,
256                                         domain_sid,
257                                         &domain_handle);
258         if (!NT_STATUS_IS_OK(status)) {
259                 werr = ntstatus_to_werror(status);
260                 goto done;
261         }
262
263         init_lsa_String(&lsa_account_name, info1->usri1_name);
264
265         status = rpccli_samr_CreateUser2(pipe_cli, ctx,
266                                          &domain_handle,
267                                          &lsa_account_name,
268                                          ACB_NORMAL,
269                                          SEC_STD_WRITE_DAC |
270                                          SEC_STD_DELETE |
271                                          SAMR_USER_ACCESS_SET_PASSWORD |
272                                          SAMR_USER_ACCESS_SET_ATTRIBUTES |
273                                          SAMR_USER_ACCESS_GET_ATTRIBUTES,
274                                          &user_handle,
275                                          &access_granted,
276                                          &rid);
277         if (!NT_STATUS_IS_OK(status)) {
278                 werr = ntstatus_to_werror(status);
279                 goto done;
280         }
281
282         status = rpccli_samr_QueryUserInfo(pipe_cli, ctx,
283                                            &user_handle,
284                                            16,
285                                            &user_info);
286         if (!NT_STATUS_IS_OK(status)) {
287                 werr = ntstatus_to_werror(status);
288                 goto done;
289         }
290
291         if (!(user_info->info16.acct_flags & ACB_NORMAL)) {
292                 werr = WERR_INVALID_PARAM;
293                 goto done;
294         }
295
296         status = rpccli_samr_GetUserPwInfo(pipe_cli, ctx,
297                                            &user_handle,
298                                            &pw_info);
299         if (!NT_STATUS_IS_OK(status)) {
300                 werr = ntstatus_to_werror(status);
301                 goto done;
302         }
303
304         ZERO_STRUCTP(user_info);
305
306         convert_USER_INFO_1_to_samr_user_info25(info1,
307                                                 &cli->user_session_key,
308                                                 &info25);
309
310         if (info1->usri1_password) {
311                 user_info->info25 = info25;
312                 status = rpccli_samr_SetUserInfo2(pipe_cli, ctx,
313                                                   &user_handle,
314                                                   25,
315                                                   user_info);
316         } else {
317                 user_info->info21 = info25.info;
318                 status = rpccli_samr_SetUserInfo(pipe_cli, ctx,
319                                                  &user_handle,
320                                                  21,
321                                                  user_info);
322
323         }
324         if (!NT_STATUS_IS_OK(status)) {
325                 werr = ntstatus_to_werror(status);
326                 goto failed;
327         }
328
329         werr = WERR_OK;
330         goto done;
331
332  failed:
333         status = rpccli_samr_DeleteUser(pipe_cli, ctx,
334                                         &user_handle);
335         if (!NT_STATUS_IS_OK(status)) {
336                 werr = ntstatus_to_werror(status);
337                 goto done;
338         }
339
340  done:
341         if (!cli) {
342                 return werr;
343         }
344
345         if (is_valid_policy_hnd(&user_handle)) {
346                 rpccli_samr_Close(pipe_cli, ctx, &user_handle);
347         }
348         if (is_valid_policy_hnd(&domain_handle)) {
349                 rpccli_samr_Close(pipe_cli, ctx, &domain_handle);
350         }
351         if (is_valid_policy_hnd(&connect_handle)) {
352                 rpccli_samr_Close(pipe_cli, ctx, &connect_handle);
353         }
354
355         cli_shutdown(cli);
356
357         return werr;
358 }