00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025 #include "includes.h"
00026 #include "winbindd.h"
00027
00028 #undef DBGC_CLASS
00029 #define DBGC_CLASS DBGC_WINBIND
00030
00031 static BOOL fillup_pw_field(const char *lp_template,
00032 const char *username,
00033 const char *domname,
00034 uid_t uid,
00035 gid_t gid,
00036 const char *in,
00037 fstring out)
00038 {
00039 char *templ;
00040
00041 if (out == NULL)
00042 return False;
00043
00044
00045
00046
00047
00048
00049
00050 if ( in && !strequal(in,"") && lp_security() == SEC_ADS ) {
00051 templ = talloc_sub_specified(NULL, in,
00052 username, domname,
00053 uid, gid);
00054 } else {
00055 templ = talloc_sub_specified(NULL, lp_template,
00056 username, domname,
00057 uid, gid);
00058 }
00059
00060 if (!templ)
00061 return False;
00062
00063 safe_strcpy(out, templ, sizeof(fstring) - 1);
00064 TALLOC_FREE(templ);
00065
00066 return True;
00067
00068 }
00069
00070
00071 static BOOL winbindd_fill_pwent(char *dom_name, char *user_name,
00072 DOM_SID *user_sid, DOM_SID *group_sid,
00073 char *full_name, char *homedir, char *shell,
00074 struct winbindd_pw *pw)
00075 {
00076 fstring output_username;
00077 fstring sid_string;
00078
00079 if (!pw || !dom_name || !user_name)
00080 return False;
00081
00082
00083
00084 if (!NT_STATUS_IS_OK(idmap_sid_to_uid(user_sid, &pw->pw_uid))) {
00085 DEBUG(1, ("error getting user id for sid %s\n", sid_to_string(sid_string, user_sid)));
00086 return False;
00087 }
00088
00089
00090
00091 if (!NT_STATUS_IS_OK(idmap_sid_to_gid(group_sid, &pw->pw_gid))) {
00092 DEBUG(1, ("error getting group id for sid %s\n", sid_to_string(sid_string, group_sid)));
00093 return False;
00094 }
00095
00096 strlower_m(user_name);
00097
00098
00099
00100 fill_domain_username(output_username, dom_name, user_name, True);
00101
00102 safe_strcpy(pw->pw_name, output_username, sizeof(pw->pw_name) - 1);
00103
00104
00105
00106 safe_strcpy(pw->pw_gecos, full_name, sizeof(pw->pw_gecos) - 1);
00107
00108
00109
00110
00111
00112 if (!fillup_pw_field(lp_template_homedir(), user_name, dom_name,
00113 pw->pw_uid, pw->pw_gid, homedir, pw->pw_dir))
00114 return False;
00115
00116 if (!fillup_pw_field(lp_template_shell(), user_name, dom_name,
00117 pw->pw_uid, pw->pw_gid, shell, pw->pw_shell))
00118 return False;
00119
00120
00121
00122
00123 safe_strcpy(pw->pw_passwd, "*", sizeof(pw->pw_passwd) - 1);
00124
00125 return True;
00126 }
00127
00128
00129
00130 enum winbindd_result winbindd_dual_userinfo(struct winbindd_domain *domain,
00131 struct winbindd_cli_state *state)
00132 {
00133 DOM_SID sid;
00134 WINBIND_USERINFO user_info;
00135 NTSTATUS status;
00136
00137
00138 state->request.data.sid[sizeof(state->request.data.sid)-1]='\0';
00139
00140 DEBUG(3, ("[%5lu]: lookupsid %s\n", (unsigned long)state->pid,
00141 state->request.data.sid));
00142
00143 if (!string_to_sid(&sid, state->request.data.sid)) {
00144 DEBUG(5, ("%s not a SID\n", state->request.data.sid));
00145 return WINBINDD_ERROR;
00146 }
00147
00148 status = domain->methods->query_user(domain, state->mem_ctx,
00149 &sid, &user_info);
00150 if (!NT_STATUS_IS_OK(status)) {
00151 DEBUG(1, ("error getting user info for sid %s\n",
00152 sid_string_static(&sid)));
00153 return WINBINDD_ERROR;
00154 }
00155
00156 fstrcpy(state->response.data.user_info.acct_name, user_info.acct_name);
00157 fstrcpy(state->response.data.user_info.full_name, user_info.full_name);
00158 fstrcpy(state->response.data.user_info.homedir, user_info.homedir);
00159 fstrcpy(state->response.data.user_info.shell, user_info.shell);
00160 state->response.data.user_info.primary_gid = user_info.primary_gid;
00161 if (!sid_peek_check_rid(&domain->sid, &user_info.group_sid,
00162 &state->response.data.user_info.group_rid)) {
00163 DEBUG(1, ("Could not extract group rid out of %s\n",
00164 sid_string_static(&sid)));
00165 return WINBINDD_ERROR;
00166 }
00167
00168 return WINBINDD_OK;
00169 }
00170
00171 struct getpwsid_state {
00172 struct winbindd_cli_state *state;
00173 struct winbindd_domain *domain;
00174 char *username;
00175 char *fullname;
00176 char *homedir;
00177 char *shell;
00178 DOM_SID user_sid;
00179 uid_t uid;
00180 DOM_SID group_sid;
00181 gid_t gid;
00182 };
00183
00184 static void getpwsid_queryuser_recv(void *private_data, BOOL success,
00185 const char *acct_name,
00186 const char *full_name,
00187 const char *homedir,
00188 const char *shell,
00189 uint32 gid,
00190 uint32 group_rid);
00191 static void getpwsid_sid2uid_recv(void *private_data, BOOL success, uid_t uid);
00192 static void getpwsid_sid2gid_recv(void *private_data, BOOL success, gid_t gid);
00193
00194 static void winbindd_getpwsid(struct winbindd_cli_state *state,
00195 const DOM_SID *sid)
00196 {
00197 struct getpwsid_state *s;
00198
00199 s = TALLOC_ZERO_P(state->mem_ctx, struct getpwsid_state);
00200 if (s == NULL) {
00201 DEBUG(0, ("talloc failed\n"));
00202 goto error;
00203 }
00204
00205 s->state = state;
00206 s->domain = find_domain_from_sid_noinit(sid);
00207 if (s->domain == NULL) {
00208 DEBUG(3, ("Could not find domain for sid %s\n",
00209 sid_string_static(sid)));
00210 goto error;
00211 }
00212
00213 sid_copy(&s->user_sid, sid);
00214
00215 query_user_async(s->state->mem_ctx, s->domain, sid,
00216 getpwsid_queryuser_recv, s);
00217 return;
00218
00219 error:
00220 request_error(state);
00221 }
00222
00223 static void getpwsid_queryuser_recv(void *private_data, BOOL success,
00224 const char *acct_name,
00225 const char *full_name,
00226 const char *homedir,
00227 const char *shell,
00228 uint32 gid,
00229 uint32 group_rid)
00230 {
00231 fstring username;
00232 struct getpwsid_state *s =
00233 talloc_get_type_abort(private_data, struct getpwsid_state);
00234
00235 if (!success) {
00236 DEBUG(5, ("Could not query domain %s SID %s\n", s->domain->name,
00237 sid_string_static(&s->user_sid)));
00238 request_error(s->state);
00239 return;
00240 }
00241
00242 fstrcpy( username, acct_name );
00243 strlower_m( username );
00244 s->username = talloc_strdup(s->state->mem_ctx, username);
00245
00246 ws_name_replace( s->username, WB_REPLACE_CHAR );
00247
00248 s->fullname = talloc_strdup(s->state->mem_ctx, full_name);
00249 s->homedir = talloc_strdup(s->state->mem_ctx, homedir);
00250 s->shell = talloc_strdup(s->state->mem_ctx, shell);
00251 s->gid = gid;
00252 sid_copy(&s->group_sid, &s->domain->sid);
00253 sid_append_rid(&s->group_sid, group_rid);
00254
00255 winbindd_sid2uid_async(s->state->mem_ctx, &s->user_sid,
00256 getpwsid_sid2uid_recv, s);
00257 }
00258
00259 static void getpwsid_sid2uid_recv(void *private_data, BOOL success, uid_t uid)
00260 {
00261 struct getpwsid_state *s =
00262 talloc_get_type_abort(private_data, struct getpwsid_state);
00263
00264 if (!success) {
00265 DEBUG(5, ("Could not query uid for user %s\\%s\n",
00266 s->domain->name, s->username));
00267 request_error(s->state);
00268 return;
00269 }
00270
00271 s->uid = uid;
00272 winbindd_sid2gid_async(s->state->mem_ctx, &s->group_sid,
00273 getpwsid_sid2gid_recv, s);
00274 }
00275
00276 static void getpwsid_sid2gid_recv(void *private_data, BOOL success, gid_t gid)
00277 {
00278 struct getpwsid_state *s =
00279 talloc_get_type_abort(private_data, struct getpwsid_state);
00280 struct winbindd_pw *pw;
00281 fstring output_username;
00282
00283
00284
00285
00286
00287
00288
00289 if ( s->gid == (gid_t)-1 ) {
00290
00291 if (!success) {
00292 DEBUG(5, ("Could not query gid for user %s\\%s\n",
00293 s->domain->name, s->username));
00294 goto failed;
00295 }
00296
00297
00298 s->gid = gid;
00299 }
00300
00301 pw = &s->state->response.data.pw;
00302 pw->pw_uid = s->uid;
00303 pw->pw_gid = s->gid;
00304 fill_domain_username(output_username, s->domain->name, s->username, True);
00305 safe_strcpy(pw->pw_name, output_username, sizeof(pw->pw_name) - 1);
00306 safe_strcpy(pw->pw_gecos, s->fullname, sizeof(pw->pw_gecos) - 1);
00307
00308 if (!fillup_pw_field(lp_template_homedir(), s->username, s->domain->name,
00309 pw->pw_uid, pw->pw_gid, s->homedir, pw->pw_dir)) {
00310 DEBUG(5, ("Could not compose homedir\n"));
00311 goto failed;
00312 }
00313
00314 if (!fillup_pw_field(lp_template_shell(), s->username, s->domain->name,
00315 pw->pw_uid, pw->pw_gid, s->shell, pw->pw_shell)) {
00316 DEBUG(5, ("Could not compose shell\n"));
00317 goto failed;
00318 }
00319
00320
00321
00322
00323 safe_strcpy(pw->pw_passwd, "*", sizeof(pw->pw_passwd) - 1);
00324
00325 request_ok(s->state);
00326 return;
00327
00328 failed:
00329 request_error(s->state);
00330 }
00331
00332
00333
00334 static void getpwnam_name2sid_recv(void *private_data, BOOL success,
00335 const DOM_SID *sid, enum lsa_SidType type);
00336
00337 void winbindd_getpwnam(struct winbindd_cli_state *state)
00338 {
00339 struct winbindd_domain *domain;
00340 fstring domname, username;
00341
00342
00343 state->request.data.username[sizeof(state->request.data.username)-1]='\0';
00344
00345 DEBUG(3, ("[%5lu]: getpwnam %s\n", (unsigned long)state->pid,
00346 state->request.data.username));
00347
00348 ws_name_return( state->request.data.username, WB_REPLACE_CHAR );
00349
00350 if (!parse_domain_user(state->request.data.username, domname,
00351 username)) {
00352 DEBUG(5, ("Could not parse domain user: %s\n",
00353 state->request.data.username));
00354 request_error(state);
00355 return;
00356 }
00357
00358
00359
00360 domain = find_domain_from_name(domname);
00361
00362 if (domain == NULL) {
00363 DEBUG(7, ("could not find domain entry for domain %s\n",
00364 domname));
00365 request_error(state);
00366 return;
00367 }
00368
00369 if ( strequal(domname, lp_workgroup()) && lp_winbind_trusted_domains_only() ) {
00370 DEBUG(7,("winbindd_getpwnam: My domain -- rejecting getpwnam() for %s\\%s.\n",
00371 domname, username));
00372 request_error(state);
00373 return;
00374 }
00375
00376
00377
00378 winbindd_lookupname_async(state->mem_ctx, domname, username,
00379 getpwnam_name2sid_recv, state);
00380 }
00381
00382 static void getpwnam_name2sid_recv(void *private_data, BOOL success,
00383 const DOM_SID *sid, enum lsa_SidType type)
00384 {
00385 struct winbindd_cli_state *state =
00386 (struct winbindd_cli_state *)private_data;
00387
00388 if (!success) {
00389 DEBUG(5, ("Could not lookup name for user %s\n",
00390 state->request.data.username));
00391 request_error(state);
00392 return;
00393 }
00394
00395 if ((type != SID_NAME_USER) && (type != SID_NAME_COMPUTER)) {
00396 DEBUG(5, ("%s is not a user\n", state->request.data.username));
00397 request_error(state);
00398 return;
00399 }
00400
00401 winbindd_getpwsid(state, sid);
00402 }
00403
00404 static void getpwuid_recv(void *private_data, BOOL success, const char *sid)
00405 {
00406 struct winbindd_cli_state *state =
00407 (struct winbindd_cli_state *)private_data;
00408 DOM_SID user_sid;
00409
00410 if (!success) {
00411 DEBUG(10,("uid2sid_recv: uid [%lu] to sid mapping failed\n.",
00412 (unsigned long)(state->request.data.uid)));
00413 request_error(state);
00414 return;
00415 }
00416
00417 DEBUG(10,("uid2sid_recv: uid %lu has sid %s\n",
00418 (unsigned long)(state->request.data.uid), sid));
00419
00420 string_to_sid(&user_sid, sid);
00421 winbindd_getpwsid(state, &user_sid);
00422 }
00423
00424
00425 void winbindd_getpwuid(struct winbindd_cli_state *state)
00426 {
00427 DEBUG(3, ("[%5lu]: getpwuid %lu\n", (unsigned long)state->pid,
00428 (unsigned long)state->request.data.uid));
00429
00430
00431
00432 winbindd_uid2sid_async(state->mem_ctx, state->request.data.uid, getpwuid_recv, state);
00433 }
00434
00435
00436
00437
00438
00439
00440
00441 static BOOL winbindd_setpwent_internal(struct winbindd_cli_state *state)
00442 {
00443 struct winbindd_domain *domain;
00444
00445 DEBUG(3, ("[%5lu]: setpwent\n", (unsigned long)state->pid));
00446
00447
00448
00449 if (!lp_winbind_enum_users()) {
00450 return False;
00451 }
00452
00453
00454
00455 if (state->getpwent_state != NULL) {
00456 free_getent_state(state->getpwent_state);
00457 state->getpwent_state = NULL;
00458 }
00459
00460 #if 0
00461
00462
00463 if ( (domain_state = (struct getent_state *)malloc(sizeof(struct getent_state))) == NULL )
00464 return False;
00465
00466 ZERO_STRUCTP(domain_state);
00467
00468
00469
00470 DLIST_ADD(state->getpwent_state, domain_state);
00471 #endif
00472
00473
00474
00475 for(domain = domain_list(); domain != NULL; domain = domain->next) {
00476 struct getent_state *domain_state;
00477
00478
00479
00480
00481
00482 if ( (IS_DC || lp_winbind_trusted_domains_only())
00483 && strequal(domain->name, lp_workgroup()) )
00484 {
00485 continue;
00486 }
00487
00488
00489
00490 if ((domain_state = SMB_MALLOC_P(struct getent_state)) == NULL) {
00491 DEBUG(0, ("malloc failed\n"));
00492 return False;
00493 }
00494
00495 ZERO_STRUCTP(domain_state);
00496
00497 fstrcpy(domain_state->domain_name, domain->name);
00498
00499
00500
00501 DLIST_ADD(state->getpwent_state, domain_state);
00502 }
00503
00504 state->getpwent_initialized = True;
00505 return True;
00506 }
00507
00508 void winbindd_setpwent(struct winbindd_cli_state *state)
00509 {
00510 if (winbindd_setpwent_internal(state)) {
00511 request_ok(state);
00512 } else {
00513 request_error(state);
00514 }
00515 }
00516
00517
00518
00519 void winbindd_endpwent(struct winbindd_cli_state *state)
00520 {
00521 DEBUG(3, ("[%5lu]: endpwent\n", (unsigned long)state->pid));
00522
00523 free_getent_state(state->getpwent_state);
00524 state->getpwent_initialized = False;
00525 state->getpwent_state = NULL;
00526 request_ok(state);
00527 }
00528
00529
00530
00531
00532
00533
00534 static BOOL get_sam_user_entries(struct getent_state *ent, TALLOC_CTX *mem_ctx)
00535 {
00536 NTSTATUS status;
00537 uint32 num_entries;
00538 WINBIND_USERINFO *info;
00539 struct getpwent_user *name_list = NULL;
00540 struct winbindd_domain *domain;
00541 struct winbindd_methods *methods;
00542 unsigned int i;
00543
00544 if (ent->num_sam_entries)
00545 return False;
00546
00547 if (!(domain = find_domain_from_name(ent->domain_name))) {
00548 DEBUG(3, ("no such domain %s in get_sam_user_entries\n",
00549 ent->domain_name));
00550 return False;
00551 }
00552
00553 methods = domain->methods;
00554
00555
00556
00557 SAFE_FREE(ent->sam_entries);
00558 ent->num_sam_entries = 0;
00559
00560
00561
00562 num_entries = 0;
00563
00564 status = methods->query_user_list(domain, mem_ctx, &num_entries,
00565 &info);
00566
00567 if (!NT_STATUS_IS_OK(status)) {
00568 DEBUG(10,("get_sam_user_entries: query_user_list failed with %s\n",
00569 nt_errstr(status) ));
00570 return False;
00571 }
00572
00573 if (num_entries) {
00574 name_list = SMB_REALLOC_ARRAY(name_list, struct getpwent_user, ent->num_sam_entries + num_entries);
00575
00576 if (!name_list) {
00577 DEBUG(0,("get_sam_user_entries realloc failed.\n"));
00578 return False;
00579 }
00580 }
00581
00582 for (i = 0; i < num_entries; i++) {
00583
00584 if (!info[i].acct_name) {
00585 fstrcpy(name_list[ent->num_sam_entries + i].name, "");
00586 } else {
00587 fstrcpy(name_list[ent->num_sam_entries + i].name,
00588 info[i].acct_name);
00589 }
00590 if (!info[i].full_name) {
00591 fstrcpy(name_list[ent->num_sam_entries + i].gecos, "");
00592 } else {
00593 fstrcpy(name_list[ent->num_sam_entries + i].gecos,
00594 info[i].full_name);
00595 }
00596 if (!info[i].homedir) {
00597 fstrcpy(name_list[ent->num_sam_entries + i].homedir, "");
00598 } else {
00599 fstrcpy(name_list[ent->num_sam_entries + i].homedir,
00600 info[i].homedir);
00601 }
00602 if (!info[i].shell) {
00603 fstrcpy(name_list[ent->num_sam_entries + i].shell, "");
00604 } else {
00605 fstrcpy(name_list[ent->num_sam_entries + i].shell,
00606 info[i].shell);
00607 }
00608
00609
00610
00611 sid_copy(&name_list[ent->num_sam_entries+i].user_sid,
00612 &info[i].user_sid);
00613 sid_copy(&name_list[ent->num_sam_entries+i].group_sid,
00614 &info[i].group_sid);
00615 }
00616
00617 ent->num_sam_entries += num_entries;
00618
00619
00620
00621 ent->sam_entries = name_list;
00622 ent->sam_entry_index = 0;
00623 return ent->num_sam_entries > 0;
00624 }
00625
00626
00627
00628 #define MAX_GETPWENT_USERS 500
00629
00630 void winbindd_getpwent(struct winbindd_cli_state *state)
00631 {
00632 struct getent_state *ent;
00633 struct winbindd_pw *user_list;
00634 int num_users, user_list_ndx;
00635
00636 DEBUG(3, ("[%5lu]: getpwent\n", (unsigned long)state->pid));
00637
00638
00639
00640 if (!lp_winbind_enum_users()) {
00641 request_error(state);
00642 return;
00643 }
00644
00645
00646
00647 num_users = MIN(MAX_GETPWENT_USERS, state->request.data.num_entries);
00648
00649 if (num_users == 0) {
00650 request_error(state);
00651 return;
00652 }
00653
00654 if ((state->response.extra_data.data = SMB_MALLOC_ARRAY(struct winbindd_pw, num_users)) == NULL) {
00655 request_error(state);
00656 return;
00657 }
00658
00659 memset(state->response.extra_data.data, 0, num_users *
00660 sizeof(struct winbindd_pw));
00661
00662 user_list = (struct winbindd_pw *)state->response.extra_data.data;
00663
00664 if (!state->getpwent_initialized)
00665 winbindd_setpwent_internal(state);
00666
00667 if (!(ent = state->getpwent_state)) {
00668 request_error(state);
00669 return;
00670 }
00671
00672
00673
00674 for (user_list_ndx = 0; user_list_ndx < num_users; ) {
00675 struct getpwent_user *name_list = NULL;
00676 uint32 result;
00677
00678
00679
00680 if (ent->num_sam_entries == ent->sam_entry_index) {
00681
00682 while(ent &&
00683 !get_sam_user_entries(ent, state->mem_ctx)) {
00684 struct getent_state *next_ent;
00685
00686
00687
00688 SAFE_FREE(ent->sam_entries);
00689
00690 next_ent = ent->next;
00691 DLIST_REMOVE(state->getpwent_state, ent);
00692
00693 SAFE_FREE(ent);
00694 ent = next_ent;
00695 }
00696
00697
00698
00699 if (!ent)
00700 break;
00701 }
00702
00703 name_list = (struct getpwent_user *)ent->sam_entries;
00704
00705
00706
00707 result = winbindd_fill_pwent(
00708 ent->domain_name,
00709 name_list[ent->sam_entry_index].name,
00710 &name_list[ent->sam_entry_index].user_sid,
00711 &name_list[ent->sam_entry_index].group_sid,
00712 name_list[ent->sam_entry_index].gecos,
00713 name_list[ent->sam_entry_index].homedir,
00714 name_list[ent->sam_entry_index].shell,
00715 &user_list[user_list_ndx]);
00716
00717
00718
00719 if (result) {
00720
00721 user_list_ndx++;
00722 state->response.data.num_entries++;
00723 state->response.length +=
00724 sizeof(struct winbindd_pw);
00725
00726 } else
00727 DEBUG(1, ("could not lookup domain user %s\n",
00728 name_list[ent->sam_entry_index].name));
00729
00730 ent->sam_entry_index++;
00731
00732 }
00733
00734
00735
00736 if (user_list_ndx > 0)
00737 request_ok(state);
00738 else
00739 request_error(state);
00740 }
00741
00742
00743
00744 void winbindd_list_users(struct winbindd_cli_state *state)
00745 {
00746 struct winbindd_domain *domain;
00747 WINBIND_USERINFO *info;
00748 const char *which_domain;
00749 uint32 num_entries = 0, total_entries = 0;
00750 char *extra_data = NULL;
00751 int extra_data_len = 0;
00752 enum winbindd_result rv = WINBINDD_ERROR;
00753
00754 DEBUG(3, ("[%5lu]: list users\n", (unsigned long)state->pid));
00755
00756
00757 state->request.domain_name[sizeof(state->request.domain_name)-1]='\0';
00758 which_domain = state->request.domain_name;
00759
00760
00761
00762 for (domain = domain_list(); domain; domain = domain->next) {
00763 NTSTATUS status;
00764 struct winbindd_methods *methods;
00765 unsigned int i;
00766
00767
00768
00769
00770
00771 if ( *which_domain && !strequal(which_domain, domain->name) )
00772 continue;
00773
00774 methods = domain->methods;
00775
00776
00777 status = methods->query_user_list(domain, state->mem_ctx,
00778 &num_entries, &info);
00779
00780 if (!NT_STATUS_IS_OK(status)) {
00781 continue;
00782 }
00783
00784 if (num_entries == 0)
00785 continue;
00786
00787
00788 total_entries += num_entries;
00789
00790 extra_data = (char *)SMB_REALLOC(
00791 extra_data, sizeof(fstring) * total_entries);
00792
00793 if (!extra_data) {
00794 DEBUG(0,("failed to enlarge buffer!\n"));
00795 goto done;
00796 }
00797
00798
00799
00800 for (i = 0; i < num_entries; i++) {
00801 fstring acct_name, name;
00802
00803 if (!info[i].acct_name) {
00804 fstrcpy(acct_name, "");
00805 } else {
00806 fstrcpy(acct_name, info[i].acct_name);
00807 }
00808
00809 fill_domain_username(name, domain->name, acct_name, True);
00810
00811
00812 memcpy(&extra_data[extra_data_len], name,
00813 strlen(name));
00814 extra_data_len += strlen(name);
00815 extra_data[extra_data_len++] = ',';
00816 }
00817 }
00818
00819
00820
00821 if (extra_data) {
00822 extra_data[extra_data_len - 1] = '\0';
00823 state->response.extra_data.data = extra_data;
00824 state->response.length += extra_data_len;
00825 }
00826
00827
00828
00829
00830 rv = WINBINDD_OK;
00831
00832 done:
00833
00834 if (rv == WINBINDD_OK)
00835 request_ok(state);
00836 else
00837 request_error(state);
00838 }