server: intialize aux_header buffer to null if the data is missing.
[tridge/openchange.git] / branches / plugfest / libmapiadmin / mapiadmin_user.c
1 /*
2    OpenChange Exchange Administration library.
3
4    Based on the work by Andrew Tridgell, 2004
5
6    Original source code available in SAMBA_4_0:
7    source/torture/rpc/testjoin.c
8
9    Copyright (C) Julien Kerihuel 2007-2010.
10
11    SAMR related code
12
13    This program is free software; you can redistribute it and/or modify
14    it under the terms of the GNU General Public License as published by
15    the Free Software Foundation; either version 3 of the License, or
16    (at your option) any later version.
17    
18    This program is distributed in the hope that it will be useful,
19    but WITHOUT ANY WARRANTY; without even the implied warranty of
20    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
21    GNU General Public License for more details.
22    
23    You should have received a copy of the GNU General Public License
24    along with this program.  If not, see <http://www.gnu.org/licenses/>.
25  */
26
27 #include "libmapiadmin/libmapiadmin.h"
28
29 #include <param.h>
30 #include <credentials.h>
31 #include <ldb_errors.h>
32 #include <ldb_wrap.h>
33 #include <ldap_ndr.h>
34
35 #include <core/error.h>
36 #include <gen_ndr/ndr_samr.h>
37 #include <gen_ndr/ndr_samr_c.h>
38
39 #include <time.h>
40
41 /**
42         \file
43         User management functions for mapiadmin
44 */
45
46 /**
47  * open connection so SAMR + Join Domain
48  * common code needed when adding or removing users
49  */
50 static enum MAPISTATUS mapiadmin_samr_connect(struct mapiadmin_ctx *mapiadmin_ctx,
51                                               TALLOC_CTX *mem_ctx)
52 {
53         NTSTATUS                        status;
54         struct tevent_context           *ev;
55         struct mapi_context             *mapi_ctx;
56         struct mapi_profile             *profile;
57         struct samr_Connect             c;
58         struct samr_OpenDomain          o;
59         struct samr_LookupDomain        l;
60         struct policy_handle            handle;
61         struct policy_handle            domain_handle;
62         struct lsa_String               name;
63
64         MAPI_RETVAL_IF(!mapiadmin_ctx, MAPI_E_NOT_INITIALIZED, NULL);
65         MAPI_RETVAL_IF(!mapiadmin_ctx->session, MAPI_E_NOT_INITIALIZED, NULL);
66         MAPI_RETVAL_IF(!mapiadmin_ctx->session->profile, MAPI_E_NOT_INITIALIZED, NULL);
67         MAPI_RETVAL_IF(!mapiadmin_ctx->session->profile->credentials, MAPI_E_NOT_INITIALIZED, NULL);
68         MAPI_RETVAL_IF(!mapiadmin_ctx->username, MAPI_E_NOT_INITIALIZED, NULL);
69
70         mapi_ctx = mapiadmin_ctx->session->mapi_ctx;
71         MAPI_RETVAL_IF(!mapi_ctx, MAPI_E_NOT_INITIALIZED, NULL);
72
73         profile = mapiadmin_ctx->session->profile;
74         
75         mapiadmin_ctx->user_ctx = talloc_zero(mem_ctx, struct test_join);
76         MAPI_RETVAL_IF(!mapiadmin_ctx->user_ctx, MAPI_E_NOT_ENOUGH_RESOURCES ,NULL);
77
78         DEBUG(3, ("Connecting to SAMR\n"));
79
80         ev = tevent_context_init(mem_ctx);
81
82         status = dcerpc_pipe_connect(mapiadmin_ctx->user_ctx,
83                                      &mapiadmin_ctx->user_ctx->p,
84                                      mapiadmin_ctx->dc_binding ? 
85                                      mapiadmin_ctx->dc_binding : 
86                                      mapiadmin_ctx->binding,
87                                      &ndr_table_samr,
88                                      profile->credentials, ev, mapi_ctx->lp_ctx);
89                                              
90         MAPI_RETVAL_IF(!NT_STATUS_IS_OK(status), MAPI_E_CALL_FAILED, NULL);     
91
92         profile = mapiadmin_ctx->session->profile;
93
94         c.in.system_name = NULL;
95         c.in.access_mask = SEC_FLAG_MAXIMUM_ALLOWED;
96         c.out.connect_handle = &handle;
97
98         status = dcerpc_samr_Connect_r(mapiadmin_ctx->user_ctx->p->binding_handle, mapiadmin_ctx->user_ctx, &c);
99         if (!NT_STATUS_IS_OK(status)) {
100                 const char *errstr = nt_errstr(status);
101                 if (NT_STATUS_EQUAL(status, NT_STATUS_NET_WRITE_FAULT)) {
102                         errstr = dcerpc_errstr(mapiadmin_ctx->user_ctx, mapiadmin_ctx->user_ctx->p->last_fault_code);
103                 }
104                 DEBUG(3, ("samr_Connect failed - %s\n", errstr));
105                 return MAPI_E_CALL_FAILED;
106         }
107
108         DEBUG(3, ("Opening domain %s\n", profile->domain));
109
110         name.string = profile->domain;
111         l.in.connect_handle = &handle;
112         l.in.domain_name = &name;
113
114         l.out.sid = talloc(mem_ctx, struct dom_sid2 *);
115         talloc_steal(mapiadmin_ctx->user_ctx, l.out.sid);
116
117         status = dcerpc_samr_LookupDomain_r(mapiadmin_ctx->user_ctx->p->binding_handle, mapiadmin_ctx->user_ctx, &l);
118         if (!NT_STATUS_IS_OK(status)) {
119                 DEBUG(3, ("LookupDomain failed - %s\n", nt_errstr(status)));
120                 return MAPI_E_CALL_FAILED;
121         }
122
123         mapiadmin_ctx->user_ctx->dom_sid = *l.out.sid;
124         mapiadmin_ctx->user_ctx->dom_netbios_name = talloc_strdup(mapiadmin_ctx->user_ctx, profile->domain);
125         if (!mapiadmin_ctx->user_ctx->dom_netbios_name) return MAPI_E_CALL_FAILED;
126
127         o.in.connect_handle = &handle;
128         o.in.access_mask = SEC_FLAG_MAXIMUM_ALLOWED;
129         o.in.sid = *l.out.sid;
130         o.out.domain_handle = &domain_handle;
131
132         status = dcerpc_samr_OpenDomain_r(mapiadmin_ctx->user_ctx->p->binding_handle, mapiadmin_ctx->user_ctx, &o);
133         if (!NT_STATUS_IS_OK(status)) {
134                 DEBUG(3, ("OpenDomain failed - %s\n", nt_errstr(status)));
135                 return MAPI_E_CALL_FAILED;
136         }
137
138         mapiadmin_ctx->handle = talloc_memdup(mem_ctx, &domain_handle, sizeof (struct policy_handle));
139
140         errno = 0;
141         return MAPI_E_SUCCESS;
142 }
143
144
145 struct tce_async_context {
146         int     found;
147 };
148
149 static int tce_search_callback(struct ldb_request *req, struct ldb_reply *ares)
150 {
151         struct tce_async_context        *actx = talloc_get_type(req->context, struct tce_async_context);
152         int                             ret;
153
154         switch (ares->type) {
155
156         case LDB_REPLY_ENTRY:
157                 if (ldb_msg_find_element(ares->message, "msExchMailboxGuid") != NULL) {
158                         DEBUG(3, ("[%s:%d]: msExchMailboxGuid found!\n", __FUNCTION__, __LINE__));
159                         actx->found = 1;
160                         talloc_free(ares);
161                         return ldb_request_done(req, LDB_SUCCESS);
162                 }
163                 break;
164         case LDB_REPLY_DONE:
165                 ret = 0;
166                 break;
167         default:
168                 DEBUG(3, ("[%s:%d]: unknown Reply Type ignore it\n", __FUNCTION__, __LINE__));
169                 talloc_free(ares);
170                 return LDB_ERR_OTHER;
171         }
172
173         if (talloc_free(ares) == -1) {
174                 DEBUG(3, ("[%s:%d]: talloc_free failed\n", __FUNCTION__, __LINE__));
175                 return LDB_ERR_OPERATIONS_ERROR;
176         }
177         
178         return LDB_SUCCESS;
179 }
180
181 /**
182  * Extend user attributes to be Exchange user
183  */
184 _PUBLIC_ enum MAPISTATUS mapiadmin_user_extend(struct mapiadmin_ctx *mapiadmin_ctx)
185 {
186         TALLOC_CTX                      *mem_ctx;
187         enum MAPISTATUS                 retval;
188         struct tevent_context           *ev = NULL;
189         struct mapi_context             *mapi_ctx;
190         struct mapi_profile             *profile;
191         struct ldb_context              *remote_ldb;
192         struct ldb_request              *req;
193         struct ldb_message              *msg;
194         struct ldb_result               *res;
195         struct ldb_control              **controls;
196         const char                      *control_strings[2] = { "notification:0", NULL };
197         struct tce_async_context        *tce_ctx;
198         const struct dom_sid            *dom_sid;
199         char                            *remote_ldb_url;
200         const char * const              dom_attrs[] = { "*", NULL };
201         int                             ret;
202         uint32_t                        count;
203         char                            **values;
204         const char                      *exch_attrs[7];
205         uint32_t                        i;
206         char                            *realm = NULL;
207         char                            *org = NULL;
208         const char                      *UserAccountControl;
209         struct ldb_dn                   *account_dn;
210
211         /* Sanity checks */
212         MAPI_RETVAL_IF(!mapiadmin_ctx, MAPI_E_NOT_INITIALIZED, NULL);
213         MAPI_RETVAL_IF(!mapiadmin_ctx->session, MAPI_E_NOT_INITIALIZED, NULL);
214         MAPI_RETVAL_IF(!mapiadmin_ctx->session->profile, MAPI_E_NOT_INITIALIZED, NULL);
215         MAPI_RETVAL_IF(!mapiadmin_ctx->session->profile->credentials, MAPI_E_NOT_INITIALIZED, NULL);
216         MAPI_RETVAL_IF(!mapiadmin_ctx->user_ctx, MAPI_E_NOT_INITIALIZED, NULL);
217
218         mapi_ctx = mapiadmin_ctx->session->mapi_ctx;
219         MAPI_RETVAL_IF(!mapi_ctx, MAPI_E_NOT_INITIALIZED, NULL);
220
221         profile = mapiadmin_ctx->session->profile;
222         dom_sid = mapiadmin_ctx->user_ctx->user_sid;
223
224         /* initialize memory context */
225         mem_ctx = talloc_named(NULL, 0, "mapiadmin_user_extend");
226
227         /* open LDAP connection */
228         ev = tevent_context_init(talloc_autofree_context());
229         remote_ldb_url = talloc_asprintf(mem_ctx, "ldap://%s", profile->server);
230         MAPI_RETVAL_IF(!remote_ldb_url, MAPI_E_CORRUPT_DATA, mem_ctx);
231         remote_ldb = ldb_wrap_connect(mem_ctx, ev, mapi_ctx->lp_ctx, remote_ldb_url, 
232                                       NULL, mapiadmin_ctx->session->profile->credentials, 0);
233         MAPI_RETVAL_IF(!remote_ldb, MAPI_E_NETWORK_ERROR, mem_ctx);
234
235         /* Search the user_dn */
236         account_dn = samdb_search_dn(remote_ldb, mem_ctx, NULL, 
237                                      "(&(objectSid=%s)(objectClass=user))", 
238                                      ldap_encode_ndr_dom_sid(mem_ctx, dom_sid));
239
240         ret = ldb_search(remote_ldb, mem_ctx, &res, account_dn, LDB_SCOPE_SUBTREE, dom_attrs, "(objectSid=%s)",
241                          ldap_encode_ndr_dom_sid(mem_ctx, dom_sid));
242         MAPI_RETVAL_IF(ret != LDB_SUCCESS, MAPI_E_NOT_FOUND, mem_ctx);
243         MAPI_RETVAL_IF(res->count != 1, MAPI_E_NOT_FOUND, mem_ctx);
244
245         /* Prepare a new message for modify */
246         msg = ldb_msg_new(mem_ctx);
247         MAPI_RETVAL_IF(!msg, MAPI_E_NOT_ENOUGH_RESOURCES, mem_ctx);
248
249         msg->dn = res->msgs[0]->dn;
250
251         /* message: givenName */
252         exch_attrs[0] = talloc_strdup(mem_ctx, mapiadmin_ctx->username);
253         ret = samdb_msg_add_string(remote_ldb, mem_ctx, msg, "givenName", exch_attrs[0]);
254         MAPI_RETVAL_IF((ret == -1), MAPI_E_NOT_ENOUGH_RESOURCES, mem_ctx);
255
256         /* message: userAccountControl */
257         exch_attrs[1] = talloc_asprintf(mem_ctx, "513");
258         ret = samdb_msg_add_string(remote_ldb, mem_ctx, msg, "userAccountControl", 
259                                    exch_attrs[1]);
260         MAPI_RETVAL_IF((ret == -1), MAPI_E_NOT_ENOUGH_RESOURCES, mem_ctx);
261         msg->elements[1].flags = LDB_FLAG_MOD_REPLACE;
262
263         /* message: mail */
264         retval = GetProfileAttr(profile, "ProxyAddress", &count, &values);
265         MAPI_RETVAL_IF(retval, retval, mem_ctx);
266
267         for (i = 0; i < count; i++) {
268                 if (values[i] && !strncasecmp("smtp", values[i], 4)) {
269                         realm = strchr(values[i], '@');
270                         realm += 1;
271                 }
272         }
273         MAPI_RETVAL_IF(!realm, MAPI_E_NOT_FOUND, mem_ctx);
274
275         exch_attrs[2] = talloc_asprintf(mem_ctx, "%s@%s", mapiadmin_ctx->username, realm);
276         ret = samdb_msg_add_string(remote_ldb, mem_ctx, msg, "mail", exch_attrs[2]);
277         MAPI_RETVAL_IF((ret == -1), MAPI_E_NOT_ENOUGH_RESOURCES, mem_ctx);
278
279         /* message: mailNickname */
280         exch_attrs[3] = talloc_strdup(mem_ctx, mapiadmin_ctx->username);
281         ret = samdb_msg_add_string(remote_ldb, mem_ctx, msg, "mailNickname", exch_attrs[3]);
282         MAPI_RETVAL_IF((ret == -1), MAPI_E_NOT_ENOUGH_RESOURCES, mem_ctx);
283
284         /* message: mDBUseDefaults */
285         exch_attrs[4] = talloc_asprintf(mem_ctx, "TRUE");
286         ret = samdb_msg_add_string(remote_ldb, mem_ctx, msg, 
287                                    "mDBUseDefaults", exch_attrs[4]);
288         MAPI_RETVAL_IF((ret == -1), MAPI_E_NOT_ENOUGH_RESOURCES, mem_ctx);
289
290         /* message: legacyExchangeDN */
291         org = talloc_strndup(mem_ctx, profile->mailbox,
292                              strlen(profile->mailbox) - strlen(profile->username));
293         exch_attrs[5] = talloc_asprintf(mem_ctx, "%s%s", org, mapiadmin_ctx->username);
294         talloc_free(org);
295         ret = samdb_msg_add_string(remote_ldb, mem_ctx, msg, 
296                                    "legacyExchangeDN", exch_attrs[5]);
297         MAPI_RETVAL_IF((ret == -1), MAPI_E_NOT_ENOUGH_RESOURCES, mem_ctx);
298
299         /* message: msExchHomeServerName */
300         exch_attrs[6] = talloc_strdup(mem_ctx, profile->homemdb);
301         ret = samdb_msg_add_string(remote_ldb, mem_ctx, msg, 
302                                    "msExchHomeServerName", exch_attrs[6]);
303         MAPI_RETVAL_IF((ret == -1), MAPI_E_NOT_ENOUGH_RESOURCES, mem_ctx);
304
305         /* Prior we call ldb_modify, set up async ldb request on
306          * msExchMailboxGuid 
307          */
308         req = talloc_zero(mem_ctx, struct ldb_request);
309         tce_ctx = talloc_zero(mem_ctx, struct tce_async_context);
310         controls = ldb_parse_control_strings(remote_ldb, mem_ctx, control_strings);
311
312         ret = ldb_build_search_req(&req, remote_ldb, mem_ctx, 
313                                    msg->dn,
314                                    LDB_SCOPE_BASE,
315                                    "(objectclass=*)",
316                                    NULL,
317                                    controls, 
318                                    (void *)tce_ctx, 
319                                    tce_search_callback, 
320                                    NULL);
321         DEBUG(3, (MAPIADMIN_DEBUG_STR, "ldb_build_search_req", ldb_strerror(ret)));
322         MAPI_RETVAL_IF((ret != LDB_SUCCESS), MAPI_E_CALL_FAILED, mem_ctx);
323
324         ldb_set_timeout(mem_ctx, req, 60);
325
326         ret = ldb_request(remote_ldb, req);
327         DEBUG(3, (MAPIADMIN_DEBUG_STR, "ldb_request", ldb_strerror(ret)));
328         MAPI_RETVAL_IF((ret != LDB_SUCCESS), MAPI_E_CALL_FAILED, mem_ctx);
329
330         ret = ldb_modify(remote_ldb, msg);
331         DEBUG(3, (MAPIADMIN_DEBUG_STR, "ldb_modify", ldb_strerror(ret)));
332         MAPI_RETVAL_IF((ret != LDB_SUCCESS), MAPI_E_CORRUPT_DATA, mem_ctx);
333
334         /* async search */
335         ret = ldb_wait(req->handle, LDB_WAIT_ALL);
336         DEBUG(3, (MAPIADMIN_DEBUG_STR, "ldb_wait", ldb_strerror(ret)));
337         MAPI_RETVAL_IF((ret != LDB_SUCCESS), MAPI_E_CALL_FAILED, mem_ctx);
338         MAPI_RETVAL_IF(!tce_ctx->found, MAPI_E_CALL_FAILED, mem_ctx);
339         
340         /* When successful replace UserAccountControl attr in the user
341          * record 
342          */
343         talloc_free(msg);
344         msg = ldb_msg_new(mem_ctx);
345         MAPI_RETVAL_IF(!msg, MAPI_E_NOT_ENOUGH_RESOURCES, mem_ctx);
346         msg->dn = res->msgs[0]->dn;
347
348         UserAccountControl = talloc_asprintf(mem_ctx, "66048");
349         ret = samdb_msg_add_string(remote_ldb, mem_ctx, msg, 
350                                    "UserAccountControl", UserAccountControl);
351         MAPI_RETVAL_IF((ret == -1), MAPI_E_NOT_ENOUGH_RESOURCES, mem_ctx);
352         msg->elements[0].flags = LDB_FLAG_MOD_REPLACE;
353
354         ret = ldb_modify(remote_ldb, msg);
355         DEBUG(3, (MAPIADMIN_DEBUG_STR, "ldb_modify", ldb_strerror(ret)));
356         MAPI_RETVAL_IF((ret != LDB_SUCCESS), MAPI_E_CORRUPT_DATA, mem_ctx);
357
358         /* reset errno before leaving */
359         errno = 0;
360         talloc_free(mem_ctx);
361         return MAPI_E_SUCCESS;
362 }
363
364 /**
365  * Add a user to Active Directory 
366  */
367 _PUBLIC_ enum MAPISTATUS mapiadmin_user_add(struct mapiadmin_ctx *mapiadmin_ctx)
368 {
369         TALLOC_CTX                      *mem_ctx;
370         NTSTATUS                        status;
371         enum MAPISTATUS                 retval;
372         struct mapi_context             *mapi_ctx;
373         struct mapi_profile             *profile;
374         struct samr_CreateUser2         r;
375         struct samr_GetUserPwInfo       pwp;
376         struct samr_SetUserInfo         s;
377         union samr_UserInfo             u;
378         uint32_t                        access_granted;
379         uint32_t                        rid;
380         DATA_BLOB                       session_key;
381         struct lsa_String               name;
382         int                             policy_min_pw_len = 0;
383
384         mem_ctx = talloc_named(NULL, 0, "mapiadmin_user_add");
385
386         retval = mapiadmin_samr_connect(mapiadmin_ctx, mem_ctx);
387         MAPI_RETVAL_IF(retval, retval, mem_ctx);
388
389         DEBUG(3, ("Creating account %s\n", mapiadmin_ctx->username));
390         profile = mapiadmin_ctx->session->profile;
391
392         mapi_ctx = mapiadmin_ctx->session->mapi_ctx;
393         MAPI_RETVAL_IF(!mapi_ctx, MAPI_E_NOT_INITIALIZED, mem_ctx);
394
395 again:
396         name.string = mapiadmin_ctx->username;
397         r.in.domain_handle = mapiadmin_ctx->handle;
398         r.in.account_name = &name;
399         r.in.acct_flags = ACB_NORMAL;
400         r.in.access_mask = SEC_FLAG_MAXIMUM_ALLOWED;
401         r.out.user_handle = &mapiadmin_ctx->user_ctx->user_handle;
402         r.out.access_granted = &access_granted;
403         r.out.rid = &rid;
404
405         status = dcerpc_samr_CreateUser2_r(mapiadmin_ctx->user_ctx->p->binding_handle, mapiadmin_ctx->user_ctx, &r);
406
407         if (NT_STATUS_EQUAL(status, NT_STATUS_USER_EXISTS)) {
408                 mapiadmin_user_del(mapiadmin_ctx);
409                 if (NT_STATUS_IS_OK(status)) {
410                         goto again;
411                 } else {
412                         MAPI_RETVAL_IF(1,MAPI_E_CALL_FAILED,mem_ctx);
413                 }
414         }
415
416         if (!NT_STATUS_IS_OK(status)) {
417                 DEBUG(3, ("CreateUser2 failed - %s\n", nt_errstr(status)));
418                 MAPI_RETVAL_IF(1,MAPI_E_CALL_FAILED,mem_ctx);
419         }
420
421         mapiadmin_ctx->user_ctx->user_sid = dom_sid_add_rid(mapiadmin_ctx->user_ctx, mapiadmin_ctx->user_ctx->dom_sid, rid);
422
423         pwp.in.user_handle = &mapiadmin_ctx->user_ctx->user_handle;
424         pwp.out.info = talloc_zero(mem_ctx, struct samr_PwInfo);
425
426         status = dcerpc_samr_GetUserPwInfo_r(mapiadmin_ctx->user_ctx->p->binding_handle, mapiadmin_ctx->user_ctx, &pwp);
427         if (NT_STATUS_IS_OK(status)) {
428                 policy_min_pw_len = pwp.out.info->min_password_length;
429         } else {
430                 DEBUG(3, ("GetUserPwInfo failed - %s\n", nt_errstr(status)));
431                 MAPI_RETVAL_IF(1,MAPI_E_CALL_FAILED,mem_ctx);
432         }
433
434         if (!mapiadmin_ctx->password) {
435                 mapiadmin_ctx->password = generate_random_str(mapiadmin_ctx->user_ctx, MAX(8, policy_min_pw_len));
436         }
437
438         DEBUG(3, ("Setting account password '%s'\n", mapiadmin_ctx->password));
439
440         ZERO_STRUCT(u);
441         s.in.user_handle = &mapiadmin_ctx->user_ctx->user_handle;
442         s.in.info = &u;
443         s.in.level = 24;
444
445         encode_pw_buffer(u.info24.password.data, mapiadmin_ctx->password, STR_UNICODE);
446         u.info24.password_expired = 0;
447
448         status = dcerpc_fetch_session_key(mapiadmin_ctx->user_ctx->p, &session_key);
449         if (!NT_STATUS_IS_OK(status)) {
450                 DEBUG(3, ("SetUserInfo level %d - no session key - %s\n",
451                           s.in.level, nt_errstr(status)));
452                 mapiadmin_user_del(mapiadmin_ctx);
453                 MAPI_RETVAL_IF(1,MAPI_E_CALL_FAILED,mem_ctx);
454         }
455
456         arcfour_crypt_blob(u.info24.password.data, 516, &session_key);
457
458         status = dcerpc_samr_SetUserInfo_r(mapiadmin_ctx->user_ctx->p->binding_handle, mapiadmin_ctx->user_ctx, &s);
459         if (!NT_STATUS_IS_OK(status)) {
460                 DEBUG(3, ("SetUserInfo failed - %s\n", nt_errstr(status)));
461                 if (NT_STATUS_EQUAL(status, NT_STATUS_PASSWORD_RESTRICTION)) {
462                         MAPI_RETVAL_IF(1, MAPI_E_BAD_VALUE, mem_ctx);
463                 } else {
464                         MAPI_RETVAL_IF(1, MAPI_E_CALL_FAILED, mem_ctx);
465                 }
466         }
467
468         ZERO_STRUCT(u);
469         s.in.user_handle = &mapiadmin_ctx->user_ctx->user_handle;
470         s.in.info = &u;
471         s.in.level = 21;
472
473         u.info21.acct_flags = ACB_NORMAL | ACB_PWNOEXP;
474         u.info21.fields_present = SAMR_FIELD_ACCT_FLAGS | SAMR_FIELD_DESCRIPTION | SAMR_FIELD_COMMENT | SAMR_FIELD_FULL_NAME;
475
476         u.info21.comment.string = talloc_asprintf(mapiadmin_ctx->user_ctx, 
477                                                   mapiadmin_ctx->comment ? 
478                                                   mapiadmin_ctx->comment :
479                                                   "Created by OpenChange: %s", 
480                                                   timestring(mapiadmin_ctx->user_ctx, time(NULL)));
481         
482         u.info21.full_name.string = talloc_asprintf(mapiadmin_ctx->user_ctx, 
483                                                     mapiadmin_ctx->fullname ?
484                                                     mapiadmin_ctx->fullname :
485                                                     "Account for OpenChange: %s", 
486                                                     timestring(mapiadmin_ctx->user_ctx, time(NULL)));
487         
488         u.info21.description.string = talloc_asprintf(mapiadmin_ctx->user_ctx, 
489                                                       mapiadmin_ctx->description ?
490                                                       mapiadmin_ctx->description :
491                                                       "OpenChange account created by host %s: %s", 
492                                          lpcfg_netbios_name(mapi_ctx->lp_ctx), 
493                                          timestring(mapiadmin_ctx->user_ctx, time(NULL)));
494
495         DEBUG(3, ("Resetting ACB flags, force pw change time\n"));
496
497         status = dcerpc_samr_SetUserInfo_r(mapiadmin_ctx->user_ctx->p->binding_handle, mapiadmin_ctx->user_ctx, &s);
498         if (!NT_STATUS_IS_OK(status)) {
499                 DEBUG(3, ("SetUserInfo failed - %s\n", nt_errstr(status)));
500                 MAPI_RETVAL_IF(1, MAPI_E_CALL_FAILED, mem_ctx);
501         }
502         retval = mapiadmin_user_extend(mapiadmin_ctx);
503         if (retval != MAPI_E_SUCCESS) {
504                 DEBUG(3, ("mapiadmin_user_extend: 0x%x\n", GetLastError()));
505                 mapiadmin_user_del(mapiadmin_ctx);
506                 MAPI_RETVAL_IF(1, MAPI_E_CALL_FAILED,mem_ctx);
507         }
508
509         talloc_free(mem_ctx);
510         return MAPI_E_SUCCESS;
511 }
512
513 /**
514  * Delete a user from Active Directory 
515  */
516 _PUBLIC_ enum MAPISTATUS mapiadmin_user_del(struct mapiadmin_ctx *mapiadmin_ctx)
517 {
518         TALLOC_CTX              *mem_ctx;
519         enum MAPISTATUS         retval;
520         NTSTATUS                status;
521         struct samr_DeleteUser  d;
522         struct policy_handle    user_handle;
523         uint32_t                rid;
524         struct samr_LookupNames n;
525         struct lsa_String       sname;
526         struct samr_OpenUser    r;
527
528         MAPI_RETVAL_IF(!mapiadmin_ctx, MAPI_E_NOT_INITIALIZED, NULL);
529         MAPI_RETVAL_IF(!mapiadmin_ctx->username, MAPI_E_NOT_INITIALIZED, NULL);
530
531         mem_ctx = talloc_named(NULL, 0, "mapiadmin_user_del");
532
533         /* Initiate SAMR connection if not already done */
534         if (!mapiadmin_ctx->user_ctx) {
535                 retval = mapiadmin_samr_connect(mapiadmin_ctx, mem_ctx);
536                 MAPI_RETVAL_IF(retval, GetLastError(), mem_ctx);                
537         }
538
539         sname.string = mapiadmin_ctx->username;
540
541         n.in.domain_handle = mapiadmin_ctx->handle;
542         n.in.num_names = 1;
543         n.in.names = &sname;
544
545         n.out.rids = talloc_zero(mem_ctx, struct samr_Ids);
546         n.out.types = talloc_zero(mem_ctx, struct samr_Ids);
547
548         status = dcerpc_samr_LookupNames_r(mapiadmin_ctx->user_ctx->p->binding_handle, mem_ctx, &n);
549         if (NT_STATUS_IS_OK(status)) {
550                 rid = n.out.rids->ids[0];
551         } else {
552                 talloc_free(mem_ctx);
553                 return MAPI_E_NOT_FOUND;
554         }
555
556         r.in.domain_handle = mapiadmin_ctx->handle;
557         r.in.access_mask = SEC_FLAG_MAXIMUM_ALLOWED;
558         r.in.rid = rid;
559         r.out.user_handle = &user_handle;
560
561         status = dcerpc_samr_OpenUser_r(mapiadmin_ctx->user_ctx->p->binding_handle, mem_ctx, &r);
562         if (!NT_STATUS_IS_OK(status)) {
563                 DEBUG(3, ("OpenUser(%s) failed - %s\n", mapiadmin_ctx->username, nt_errstr(status)));
564                 MAPI_RETVAL_IF(!NT_STATUS_IS_OK(status), MAPI_E_NOT_FOUND, mem_ctx);
565         }
566
567         d.in.user_handle = &user_handle;
568         d.out.user_handle = &user_handle;
569         status = dcerpc_samr_DeleteUser_r(mapiadmin_ctx->user_ctx->p->binding_handle, mem_ctx, &d);
570         MAPI_RETVAL_IF(!NT_STATUS_IS_OK(status), MAPI_E_CALL_FAILED, mem_ctx);
571
572         talloc_free(mem_ctx);
573         return MAPI_E_SUCCESS;
574 }
575
576 _PUBLIC_ enum MAPISTATUS mapiadmin_user_mod(struct mapiadmin_ctx *mapiadmin)
577 {
578         return MAPI_E_NO_SUPPORT;
579 }