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