r11336: Start to get my control back :-). Volker, I think
[sfrench/samba-autobuild/.git] / source3 / rpc_client / cli_lsarpc.c
1 /* 
2    Unix SMB/CIFS implementation.
3    RPC pipe client
4    Copyright (C) Tim Potter                        2000-2001,
5    Copyright (C) Andrew Tridgell              1992-1997,2000,
6    Copyright (C) Rafal Szczesniak                       2002
7    Copyright (C) Jeremy Allison                         2005.
8    
9    This program is free software; you can redistribute it and/or modify
10    it under the terms of the GNU General Public License as published by
11    the Free Software Foundation; either version 2 of the License, or
12    (at your option) any later version.
13    
14    This program is distributed in the hope that it will be useful,
15    but WITHOUT ANY WARRANTY; without even the implied warranty of
16    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
17    GNU General Public License for more details.
18    
19    You should have received a copy of the GNU General Public License
20    along with this program; if not, write to the Free Software
21    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
22 */
23
24 #include "includes.h"
25
26 /** @defgroup lsa LSA - Local Security Architecture
27  *  @ingroup rpc_client
28  *
29  * @{
30  **/
31
32 /**
33  * @file cli_lsarpc.c
34  *
35  * RPC client routines for the LSA RPC pipe.  LSA means "local
36  * security authority", which is half of a password database.
37  **/
38
39 /** Open a LSA policy handle
40  *
41  * @param cli Handle on an initialised SMB connection */
42
43 NTSTATUS rpccli_lsa_open_policy(struct rpc_pipe_client *cli,
44                                 TALLOC_CTX *mem_ctx,
45                                 BOOL sec_qos, uint32 des_access,
46                                 POLICY_HND *pol)
47 {
48         prs_struct qbuf, rbuf;
49         LSA_Q_OPEN_POL q;
50         LSA_R_OPEN_POL r;
51         LSA_SEC_QOS qos;
52         NTSTATUS result;
53
54         ZERO_STRUCT(q);
55         ZERO_STRUCT(r);
56
57         /* Initialise input parameters */
58
59         if (sec_qos) {
60                 init_lsa_sec_qos(&qos, 2, 1, 0);
61                 init_q_open_pol(&q, '\\', 0, des_access, &qos);
62         } else {
63                 init_q_open_pol(&q, '\\', 0, des_access, NULL);
64         }
65
66         /* Marshall data and send request */
67
68         CLI_DO_RPC( cli, mem_ctx, PI_LSARPC, LSA_OPENPOLICY,
69                         q, r,
70                         qbuf, rbuf,
71                         lsa_io_q_open_pol,
72                         lsa_io_r_open_pol,
73                         NT_STATUS_UNSUCCESSFUL );
74
75         /* Return output parameters */
76
77         result = r.status;
78
79         if (NT_STATUS_IS_OK(result)) {
80                 *pol = r.pol;
81 #ifdef __INSURE__
82                 pol->marker = MALLOC(1);
83 #endif
84         }
85
86         return result;
87 }
88
89 /** Open a LSA policy handle
90   *
91   * @param cli Handle on an initialised SMB connection 
92   */
93
94 NTSTATUS rpccli_lsa_open_policy2(struct rpc_pipe_client *cli,
95                                  TALLOC_CTX *mem_ctx, BOOL sec_qos,
96                                  uint32 des_access, POLICY_HND *pol)
97 {
98         prs_struct qbuf, rbuf;
99         LSA_Q_OPEN_POL2 q;
100         LSA_R_OPEN_POL2 r;
101         LSA_SEC_QOS qos;
102         NTSTATUS result;
103         char *srv_name_slash = talloc_asprintf(mem_ctx, "\\\\%s", cli->cli->desthost);
104
105         ZERO_STRUCT(q);
106         ZERO_STRUCT(r);
107
108         if (sec_qos) {
109                 init_lsa_sec_qos(&qos, 2, 1, 0);
110                 init_q_open_pol2(&q, srv_name_slash, 0, des_access, &qos);
111         } else {
112                 init_q_open_pol2(&q, srv_name_slash, 0, des_access, NULL);
113         }
114
115         CLI_DO_RPC( cli, mem_ctx, PI_LSARPC, LSA_OPENPOLICY2,
116                         q, r,
117                         qbuf, rbuf,
118                         lsa_io_q_open_pol2,
119                         lsa_io_r_open_pol2,
120                         NT_STATUS_UNSUCCESSFUL );
121
122         /* Return output parameters */
123
124         result = r.status;
125
126         if (NT_STATUS_IS_OK(result)) {
127                 *pol = r.pol;
128 #ifdef __INSURE__
129                 pol->marker = (char *)malloc(1);
130 #endif
131         }
132
133         return result;
134 }
135
136 /** Close a LSA policy handle */
137
138 NTSTATUS rpccli_lsa_close(struct rpc_pipe_client *cli, TALLOC_CTX *mem_ctx, 
139                           POLICY_HND *pol)
140 {
141         prs_struct qbuf, rbuf;
142         LSA_Q_CLOSE q;
143         LSA_R_CLOSE r;
144         NTSTATUS result;
145
146         ZERO_STRUCT(q);
147         ZERO_STRUCT(r);
148
149         init_lsa_q_close(&q, pol);
150
151         CLI_DO_RPC( cli, mem_ctx, PI_LSARPC, LSA_CLOSE,
152                         q, r,
153                         qbuf, rbuf,
154                         lsa_io_q_close,
155                         lsa_io_r_close,
156                         NT_STATUS_UNSUCCESSFUL );
157
158         /* Return output parameters */
159
160         result = r.status;
161
162         if (NT_STATUS_IS_OK(result)) {
163 #ifdef __INSURE__
164                 SAFE_FREE(pol->marker);
165 #endif
166                 *pol = r.pol;
167         }
168
169         return result;
170 }
171
172 /** Lookup a list of sids */
173
174 NTSTATUS rpccli_lsa_lookup_sids(struct rpc_pipe_client *cli,
175                                 TALLOC_CTX *mem_ctx,
176                                 POLICY_HND *pol, int num_sids,
177                                 const DOM_SID *sids, 
178                                 char ***domains, char ***names, uint32 **types)
179 {
180         prs_struct qbuf, rbuf;
181         LSA_Q_LOOKUP_SIDS q;
182         LSA_R_LOOKUP_SIDS r;
183         DOM_R_REF ref;
184         LSA_TRANS_NAME_ENUM t_names;
185         NTSTATUS result = NT_STATUS_OK;
186         int i;
187
188         ZERO_STRUCT(q);
189         ZERO_STRUCT(r);
190
191         init_q_lookup_sids(mem_ctx, &q, pol, num_sids, sids, 1);
192
193         ZERO_STRUCT(ref);
194         ZERO_STRUCT(t_names);
195
196         r.dom_ref = &ref;
197         r.names = &t_names;
198
199         CLI_DO_RPC( cli, mem_ctx, PI_LSARPC, LSA_LOOKUPSIDS,
200                         q, r,
201                         qbuf, rbuf,
202                         lsa_io_q_lookup_sids,
203                         lsa_io_r_lookup_sids,
204                         NT_STATUS_UNSUCCESSFUL );
205
206         if (!NT_STATUS_IS_OK(r.status) &&
207             NT_STATUS_V(r.status) != NT_STATUS_V(STATUS_SOME_UNMAPPED)) {
208           
209                 /* An actual error occured */
210                 result = r.status;
211
212                 goto done;
213         }
214
215         /* Return output parameters */
216
217         if (r.mapped_count == 0) {
218                 result = NT_STATUS_NONE_MAPPED;
219                 goto done;
220         }
221
222         if (!((*domains) = TALLOC_ARRAY(mem_ctx, char *, num_sids))) {
223                 DEBUG(0, ("cli_lsa_lookup_sids(): out of memory\n"));
224                 result = NT_STATUS_UNSUCCESSFUL;
225                 goto done;
226         }
227
228         if (!((*names) = TALLOC_ARRAY(mem_ctx, char *, num_sids))) {
229                 DEBUG(0, ("cli_lsa_lookup_sids(): out of memory\n"));
230                 result = NT_STATUS_UNSUCCESSFUL;
231                 goto done;
232         }
233
234         if (!((*types) = TALLOC_ARRAY(mem_ctx, uint32, num_sids))) {
235                 DEBUG(0, ("cli_lsa_lookup_sids(): out of memory\n"));
236                 result = NT_STATUS_UNSUCCESSFUL;
237                 goto done;
238         }
239                 
240         for (i = 0; i < num_sids; i++) {
241                 fstring name, dom_name;
242                 uint32 dom_idx = t_names.name[i].domain_idx;
243
244                 /* Translate optimised name through domain index array */
245
246                 if (dom_idx != 0xffffffff) {
247
248                         rpcstr_pull_unistr2_fstring(
249                                 dom_name, &ref.ref_dom[dom_idx].uni_dom_name);
250                         rpcstr_pull_unistr2_fstring(
251                                 name, &t_names.uni_name[i]);
252
253                         (*names)[i] = talloc_strdup(mem_ctx, name);
254                         (*domains)[i] = talloc_strdup(mem_ctx, dom_name);
255                         (*types)[i] = t_names.name[i].sid_name_use;
256                         
257                         if (((*names)[i] == NULL) || ((*domains)[i] == NULL)) {
258                                 DEBUG(0, ("cli_lsa_lookup_sids(): out of memory\n"));
259                                 result = NT_STATUS_UNSUCCESSFUL;
260                                 goto done;
261                         }
262
263                 } else {
264                         (*names)[i] = NULL;
265                         (*domains)[i] = NULL;
266                         (*types)[i] = SID_NAME_UNKNOWN;
267                 }
268         }
269
270  done:
271
272         return result;
273 }
274
275 /** Lookup a list of names */
276
277 NTSTATUS rpccli_lsa_lookup_names(struct rpc_pipe_client *cli,
278                                  TALLOC_CTX *mem_ctx,
279                                  POLICY_HND *pol, int num_names, 
280                                  const char **names, DOM_SID **sids, 
281                                  uint32 **types)
282 {
283         prs_struct qbuf, rbuf;
284         LSA_Q_LOOKUP_NAMES q;
285         LSA_R_LOOKUP_NAMES r;
286         DOM_R_REF ref;
287         NTSTATUS result;
288         int i;
289         
290         ZERO_STRUCT(q);
291         ZERO_STRUCT(r);
292
293         ZERO_STRUCT(ref);
294         r.dom_ref = &ref;
295
296         init_q_lookup_names(mem_ctx, &q, pol, num_names, names);
297
298         CLI_DO_RPC( cli, mem_ctx, PI_LSARPC, LSA_LOOKUPNAMES,
299                         q, r,
300                         qbuf, rbuf,
301                         lsa_io_q_lookup_names,
302                         lsa_io_r_lookup_names,
303                         NT_STATUS_UNSUCCESSFUL);
304
305         result = r.status;
306
307         if (!NT_STATUS_IS_OK(result) && NT_STATUS_V(result) !=
308             NT_STATUS_V(STATUS_SOME_UNMAPPED)) {
309
310                 /* An actual error occured */
311
312                 goto done;
313         }
314
315         /* Return output parameters */
316
317         if (r.mapped_count == 0) {
318                 result = NT_STATUS_NONE_MAPPED;
319                 goto done;
320         }
321
322         if (!((*sids = TALLOC_ARRAY(mem_ctx, DOM_SID, num_names)))) {
323                 DEBUG(0, ("cli_lsa_lookup_sids(): out of memory\n"));
324                 result = NT_STATUS_UNSUCCESSFUL;
325                 goto done;
326         }
327
328         if (!((*types = TALLOC_ARRAY(mem_ctx, uint32, num_names)))) {
329                 DEBUG(0, ("cli_lsa_lookup_sids(): out of memory\n"));
330                 result = NT_STATUS_UNSUCCESSFUL;
331                 goto done;
332         }
333
334         for (i = 0; i < num_names; i++) {
335                 DOM_RID2 *t_rids = r.dom_rid;
336                 uint32 dom_idx = t_rids[i].rid_idx;
337                 uint32 dom_rid = t_rids[i].rid;
338                 DOM_SID *sid = &(*sids)[i];
339
340                 /* Translate optimised sid through domain index array */
341
342                 if (dom_idx != 0xffffffff) {
343
344                         sid_copy(sid, &ref.ref_dom[dom_idx].ref_dom.sid);
345
346                         if (dom_rid != 0xffffffff) {
347                                 sid_append_rid(sid, dom_rid);
348                         }
349
350                         (*types)[i] = t_rids[i].type;
351                 } else {
352                         ZERO_STRUCTP(sid);
353                         (*types)[i] = SID_NAME_UNKNOWN;
354                 }
355         }
356
357  done:
358
359         return result;
360 }
361
362 /** Query info policy
363  *
364  *  @param domain_sid - returned remote server's domain sid */
365
366 NTSTATUS rpccli_lsa_query_info_policy(struct rpc_pipe_client *cli,
367                                       TALLOC_CTX *mem_ctx,
368                                       POLICY_HND *pol, uint16 info_class, 
369                                       char **domain_name, DOM_SID **domain_sid)
370 {
371         prs_struct qbuf, rbuf;
372         LSA_Q_QUERY_INFO q;
373         LSA_R_QUERY_INFO r;
374         NTSTATUS result;
375
376         ZERO_STRUCT(q);
377         ZERO_STRUCT(r);
378
379         init_q_query(&q, pol, info_class);
380
381         CLI_DO_RPC(cli, mem_ctx, PI_LSARPC, LSA_QUERYINFOPOLICY,
382                 q, r,
383                 qbuf, rbuf,
384                 lsa_io_q_query,
385                 lsa_io_r_query,
386                 NT_STATUS_UNSUCCESSFUL);
387
388         result = r.status;
389
390         if (!NT_STATUS_IS_OK(result)) {
391                 goto done;
392         }
393
394         /* Return output parameters */
395
396         switch (info_class) {
397
398         case 3:
399                 if (domain_name && (r.dom.id3.buffer_dom_name != 0)) {
400                         *domain_name = unistr2_tdup(mem_ctx, 
401                                                    &r.dom.id3.
402                                                    uni_domain_name);
403                 }
404
405                 if (domain_sid && (r.dom.id3.buffer_dom_sid != 0)) {
406                         *domain_sid = TALLOC_P(mem_ctx, DOM_SID);
407                         if (*domain_sid) {
408                                 sid_copy(*domain_sid, &r.dom.id3.dom_sid.sid);
409                         }
410                 }
411
412                 break;
413
414         case 5:
415                 
416                 if (domain_name && (r.dom.id5.buffer_dom_name != 0)) {
417                         *domain_name = unistr2_tdup(mem_ctx, 
418                                                    &r.dom.id5.
419                                                    uni_domain_name);
420                 }
421                         
422                 if (domain_sid && (r.dom.id5.buffer_dom_sid != 0)) {
423                         *domain_sid = TALLOC_P(mem_ctx, DOM_SID);
424                         if (*domain_sid) {
425                                 sid_copy(*domain_sid, &r.dom.id5.dom_sid.sid);
426                         }
427                 }
428                 break;
429                         
430         default:
431                 DEBUG(3, ("unknown info class %d\n", info_class));
432                 break;                
433         }
434         
435  done:
436
437         return result;
438 }
439
440 /** Query info policy2
441  *
442  *  @param domain_name - returned remote server's domain name
443  *  @param dns_name - returned remote server's dns domain name
444  *  @param forest_name - returned remote server's forest name
445  *  @param domain_guid - returned remote server's domain guid
446  *  @param domain_sid - returned remote server's domain sid */
447
448 NTSTATUS rpccli_lsa_query_info_policy2(struct rpc_pipe_client *cli,
449                                        TALLOC_CTX *mem_ctx,
450                                        POLICY_HND *pol, uint16 info_class, 
451                                        char **domain_name, char **dns_name,
452                                        char **forest_name,
453                                        struct uuid **domain_guid,
454                                        DOM_SID **domain_sid)
455 {
456         prs_struct qbuf, rbuf;
457         LSA_Q_QUERY_INFO2 q;
458         LSA_R_QUERY_INFO2 r;
459         NTSTATUS result = NT_STATUS_UNSUCCESSFUL;
460
461         if (info_class != 12)
462                 goto done;
463
464         ZERO_STRUCT(q);
465         ZERO_STRUCT(r);
466
467         init_q_query2(&q, pol, info_class);
468
469         CLI_DO_RPC( cli, mem_ctx, PI_LSARPC, LSA_QUERYINFO2,
470                 q, r,
471                 qbuf, rbuf,
472                 lsa_io_q_query_info2,
473                 lsa_io_r_query_info2,
474                 NT_STATUS_UNSUCCESSFUL);
475
476         result = r.status;
477
478         if (!NT_STATUS_IS_OK(result)) {
479                 goto done;
480         }
481
482         /* Return output parameters */
483
484         ZERO_STRUCTP(domain_guid);
485
486         if (domain_name && r.info.dns_dom_info.hdr_nb_dom_name.buffer) {
487                 *domain_name = unistr2_tdup(mem_ctx, 
488                                             &r.info.dns_dom_info
489                                             .uni_nb_dom_name);
490         }
491         if (dns_name && r.info.dns_dom_info.hdr_dns_dom_name.buffer) {
492                 *dns_name = unistr2_tdup(mem_ctx, 
493                                          &r.info.dns_dom_info
494                                          .uni_dns_dom_name);
495         }
496         if (forest_name && r.info.dns_dom_info.hdr_forest_name.buffer) {
497                 *forest_name = unistr2_tdup(mem_ctx, 
498                                             &r.info.dns_dom_info
499                                             .uni_forest_name);
500         }
501         
502         if (domain_guid) {
503                 *domain_guid = TALLOC_P(mem_ctx, struct uuid);
504                 memcpy(*domain_guid, 
505                        &r.info.dns_dom_info.dom_guid, 
506                        sizeof(struct uuid));
507         }
508
509         if (domain_sid && r.info.dns_dom_info.ptr_dom_sid != 0) {
510                 *domain_sid = TALLOC_P(mem_ctx, DOM_SID);
511                 if (*domain_sid) {
512                         sid_copy(*domain_sid, 
513                                  &r.info.dns_dom_info.dom_sid.sid);
514                 }
515         }
516         
517  done:
518
519         return result;
520 }
521
522 /**
523  * Enumerate list of trusted domains
524  *
525  * @param cli client state (cli_state) structure of the connection
526  * @param mem_ctx memory context
527  * @param pol opened lsa policy handle
528  * @param enum_ctx enumeration context ie. index of first returned domain entry
529  * @param pref_num_domains preferred max number of entries returned in one response
530  * @param num_domains total number of trusted domains returned by response
531  * @param domain_names returned trusted domain names
532  * @param domain_sids returned trusted domain sids
533  *
534  * @return nt status code of response
535  **/
536
537 NTSTATUS rpccli_lsa_enum_trust_dom(struct rpc_pipe_client *cli,
538                                    TALLOC_CTX *mem_ctx,
539                                    POLICY_HND *pol, uint32 *enum_ctx, 
540                                    uint32 *num_domains,
541                                    char ***domain_names, DOM_SID **domain_sids)
542 {
543         prs_struct qbuf, rbuf;
544         LSA_Q_ENUM_TRUST_DOM in;
545         LSA_R_ENUM_TRUST_DOM out;
546         int i;
547         fstring tmp;
548
549         ZERO_STRUCT(in);
550         ZERO_STRUCT(out);
551
552         /* 64k is enough for about 2000 trusted domains */
553         
554         init_q_enum_trust_dom(&in, pol, *enum_ctx, 0x10000);
555
556         CLI_DO_RPC( cli, mem_ctx, PI_LSARPC, LSA_ENUMTRUSTDOM, 
557                     in, out, 
558                     qbuf, rbuf,
559                     lsa_io_q_enum_trust_dom,
560                     lsa_io_r_enum_trust_dom, 
561                     NT_STATUS_UNSUCCESSFUL );
562
563
564         /* check for an actual error */
565
566         if ( !NT_STATUS_IS_OK(out.status) 
567                 && !NT_STATUS_EQUAL(out.status, NT_STATUS_NO_MORE_ENTRIES) 
568                 && !NT_STATUS_EQUAL(out.status, STATUS_MORE_ENTRIES) )
569         {
570                 return out.status;
571         }
572                 
573         /* Return output parameters */
574
575         *num_domains  = out.count;
576         *enum_ctx     = out.enum_context;
577         
578         if ( out.count ) {
579
580                 /* Allocate memory for trusted domain names and sids */
581
582                 if ( !(*domain_names = TALLOC_ARRAY(mem_ctx, char *, out.count)) ) {
583                         DEBUG(0, ("cli_lsa_enum_trust_dom(): out of memory\n"));
584                         return NT_STATUS_NO_MEMORY;
585                 }
586
587                 if ( !(*domain_sids = TALLOC_ARRAY(mem_ctx, DOM_SID, out.count)) ) {
588                         DEBUG(0, ("cli_lsa_enum_trust_dom(): out of memory\n"));
589                         return NT_STATUS_NO_MEMORY;
590                 }
591
592                 /* Copy across names and sids */
593
594                 for (i = 0; i < out.count; i++) {
595
596                         rpcstr_pull( tmp, out.domlist->domains[i].name.string->buffer, 
597                                 sizeof(tmp), out.domlist->domains[i].name.length, 0);
598                         (*domain_names)[i] = talloc_strdup(mem_ctx, tmp);
599
600                         sid_copy(&(*domain_sids)[i], &out.domlist->domains[i].sid->sid );
601                 }
602         }
603
604         return out.status;
605 }
606
607 /** Enumerate privileges*/
608
609 NTSTATUS rpccli_lsa_enum_privilege(struct rpc_pipe_client *cli, TALLOC_CTX *mem_ctx,
610                                 POLICY_HND *pol, uint32 *enum_context, uint32 pref_max_length,
611                                 uint32 *count, char ***privs_name, uint32 **privs_high, uint32 **privs_low)
612 {
613         prs_struct qbuf, rbuf;
614         LSA_Q_ENUM_PRIVS q;
615         LSA_R_ENUM_PRIVS r;
616         NTSTATUS result;
617         int i;
618
619         ZERO_STRUCT(q);
620         ZERO_STRUCT(r);
621
622         init_q_enum_privs(&q, pol, *enum_context, pref_max_length);
623
624         CLI_DO_RPC( cli, mem_ctx, PI_LSARPC, LSA_ENUM_PRIVS,
625                 q, r,
626                 qbuf, rbuf,
627                 lsa_io_q_enum_privs,
628                 lsa_io_r_enum_privs,
629                 NT_STATUS_UNSUCCESSFUL);
630
631         result = r.status;
632
633         if (!NT_STATUS_IS_OK(result)) {
634                 goto done;
635         }
636
637         /* Return output parameters */
638
639         *enum_context = r.enum_context;
640         *count = r.count;
641
642         if (!((*privs_name = TALLOC_ARRAY(mem_ctx, char *, r.count)))) {
643                 DEBUG(0, ("(cli_lsa_enum_privilege): out of memory\n"));
644                 result = NT_STATUS_UNSUCCESSFUL;
645                 goto done;
646         }
647
648         if (!((*privs_high = TALLOC_ARRAY(mem_ctx, uint32, r.count)))) {
649                 DEBUG(0, ("(cli_lsa_enum_privilege): out of memory\n"));
650                 result = NT_STATUS_UNSUCCESSFUL;
651                 goto done;
652         }
653
654         if (!((*privs_low = TALLOC_ARRAY(mem_ctx, uint32, r.count)))) {
655                 DEBUG(0, ("(cli_lsa_enum_privilege): out of memory\n"));
656                 result = NT_STATUS_UNSUCCESSFUL;
657                 goto done;
658         }
659
660         for (i = 0; i < r.count; i++) {
661                 fstring name;
662
663                 rpcstr_pull_unistr2_fstring( name, &r.privs[i].name);
664
665                 (*privs_name)[i] = talloc_strdup(mem_ctx, name);
666
667                 (*privs_high)[i] = r.privs[i].luid_high;
668                 (*privs_low)[i] = r.privs[i].luid_low;
669         }
670
671  done:
672
673         return result;
674 }
675
676 /** Get privilege name */
677
678 NTSTATUS rpccli_lsa_get_dispname(struct rpc_pipe_client *cli, TALLOC_CTX *mem_ctx,
679                               POLICY_HND *pol, const char *name, 
680                               uint16 lang_id, uint16 lang_id_sys,
681                               fstring description, uint16 *lang_id_desc)
682 {
683         prs_struct qbuf, rbuf;
684         LSA_Q_PRIV_GET_DISPNAME q;
685         LSA_R_PRIV_GET_DISPNAME r;
686         NTSTATUS result;
687
688         ZERO_STRUCT(q);
689         ZERO_STRUCT(r);
690
691         init_lsa_priv_get_dispname(&q, pol, name, lang_id, lang_id_sys);
692
693         CLI_DO_RPC( cli, mem_ctx, PI_LSARPC, LSA_PRIV_GET_DISPNAME,
694                 q, r,
695                 qbuf, rbuf,
696                 lsa_io_q_priv_get_dispname,
697                 lsa_io_r_priv_get_dispname,
698                 NT_STATUS_UNSUCCESSFUL);
699
700         result = r.status;
701
702         if (!NT_STATUS_IS_OK(result)) {
703                 goto done;
704         }
705
706         /* Return output parameters */
707         
708         rpcstr_pull_unistr2_fstring(description , &r.desc);
709         *lang_id_desc = r.lang_id;
710
711  done:
712
713         return result;
714 }
715
716 /** Enumerate list of SIDs  */
717
718 NTSTATUS rpccli_lsa_enum_sids(struct rpc_pipe_client *cli, TALLOC_CTX *mem_ctx,
719                                 POLICY_HND *pol, uint32 *enum_ctx, uint32 pref_max_length, 
720                                 uint32 *num_sids, DOM_SID **sids)
721 {
722         prs_struct qbuf, rbuf;
723         LSA_Q_ENUM_ACCOUNTS q;
724         LSA_R_ENUM_ACCOUNTS r;
725         NTSTATUS result;
726         int i;
727
728         ZERO_STRUCT(q);
729         ZERO_STRUCT(r);
730
731         init_lsa_q_enum_accounts(&q, pol, *enum_ctx, pref_max_length);
732
733         CLI_DO_RPC( cli, mem_ctx, PI_LSARPC, LSA_ENUM_ACCOUNTS,
734                 q, r,
735                 qbuf, rbuf,
736                 lsa_io_q_enum_accounts,
737                 lsa_io_r_enum_accounts,
738                 NT_STATUS_UNSUCCESSFUL);
739
740         result = r.status;
741
742         if (!NT_STATUS_IS_OK(result)) {
743                 goto done;
744         }
745
746         if (r.sids.num_entries==0)
747                 goto done;
748
749         /* Return output parameters */
750
751         *sids = TALLOC_ARRAY(mem_ctx, DOM_SID, r.sids.num_entries);
752         if (!*sids) {
753                 DEBUG(0, ("(cli_lsa_enum_sids): out of memory\n"));
754                 result = NT_STATUS_UNSUCCESSFUL;
755                 goto done;
756         }
757
758         /* Copy across names and sids */
759
760         for (i = 0; i < r.sids.num_entries; i++) {
761                 sid_copy(&(*sids)[i], &r.sids.sid[i].sid);
762         }
763
764         *num_sids= r.sids.num_entries;
765         *enum_ctx = r.enum_context;
766
767  done:
768
769         return result;
770 }
771
772 /** Create a LSA user handle
773  *
774  * @param cli Handle on an initialised SMB connection
775  *
776  * FIXME: The code is actually identical to open account
777  * TODO: Check and code what the function should exactly do
778  *
779  * */
780
781 NTSTATUS rpccli_lsa_create_account(struct rpc_pipe_client *cli, TALLOC_CTX *mem_ctx,
782                              POLICY_HND *dom_pol, DOM_SID *sid, uint32 desired_access, 
783                              POLICY_HND *user_pol)
784 {
785         prs_struct qbuf, rbuf;
786         LSA_Q_CREATEACCOUNT q;
787         LSA_R_CREATEACCOUNT r;
788         NTSTATUS result;
789
790         ZERO_STRUCT(q);
791         ZERO_STRUCT(r);
792
793         /* Initialise input parameters */
794
795         init_lsa_q_create_account(&q, dom_pol, sid, desired_access);
796
797         CLI_DO_RPC( cli, mem_ctx, PI_LSARPC, LSA_CREATEACCOUNT,
798                 q, r,
799                 qbuf, rbuf,
800                 lsa_io_q_create_account,
801                 lsa_io_r_create_account,
802                 NT_STATUS_UNSUCCESSFUL);
803
804         /* Return output parameters */
805
806         result = r.status;
807
808         if (NT_STATUS_IS_OK(result)) {
809                 *user_pol = r.pol;
810         }
811
812         return result;
813 }
814
815 /** Open a LSA user handle
816  *
817  * @param cli Handle on an initialised SMB connection */
818
819 NTSTATUS rpccli_lsa_open_account(struct rpc_pipe_client *cli, TALLOC_CTX *mem_ctx,
820                              POLICY_HND *dom_pol, DOM_SID *sid, uint32 des_access, 
821                              POLICY_HND *user_pol)
822 {
823         prs_struct qbuf, rbuf;
824         LSA_Q_OPENACCOUNT q;
825         LSA_R_OPENACCOUNT r;
826         NTSTATUS result;
827
828         ZERO_STRUCT(q);
829         ZERO_STRUCT(r);
830
831         /* Initialise input parameters */
832
833         init_lsa_q_open_account(&q, dom_pol, sid, des_access);
834
835         CLI_DO_RPC( cli, mem_ctx, PI_LSARPC, LSA_OPENACCOUNT,
836                 q, r,
837                 qbuf, rbuf,
838                 lsa_io_q_open_account,
839                 lsa_io_r_open_account,
840                 NT_STATUS_UNSUCCESSFUL);
841
842         /* Return output parameters */
843
844         result = r.status;
845
846         if (NT_STATUS_IS_OK(result)) {
847                 *user_pol = r.pol;
848         }
849
850         return result;
851 }
852
853 /** Enumerate user privileges
854  *
855  * @param cli Handle on an initialised SMB connection */
856
857 NTSTATUS rpccli_lsa_enum_privsaccount(struct rpc_pipe_client *cli, TALLOC_CTX *mem_ctx,
858                              POLICY_HND *pol, uint32 *count, LUID_ATTR **set)
859 {
860         prs_struct qbuf, rbuf;
861         LSA_Q_ENUMPRIVSACCOUNT q;
862         LSA_R_ENUMPRIVSACCOUNT r;
863         NTSTATUS result;
864         int i;
865
866         ZERO_STRUCT(q);
867         ZERO_STRUCT(r);
868
869         /* Initialise input parameters */
870
871         init_lsa_q_enum_privsaccount(&q, pol);
872
873         CLI_DO_RPC( cli, mem_ctx, PI_LSARPC, LSA_ENUMPRIVSACCOUNT,
874                 q, r,
875                 qbuf, rbuf,
876                 lsa_io_q_enum_privsaccount,
877                 lsa_io_r_enum_privsaccount,
878                 NT_STATUS_UNSUCCESSFUL);
879
880         /* Return output parameters */
881
882         result = r.status;
883
884         if (!NT_STATUS_IS_OK(result)) {
885                 goto done;
886         }
887
888         if (r.count == 0)
889                 goto done;
890
891         if (!((*set = TALLOC_ARRAY(mem_ctx, LUID_ATTR, r.count)))) {
892                 DEBUG(0, ("(cli_lsa_enum_privsaccount): out of memory\n"));
893                 result = NT_STATUS_UNSUCCESSFUL;
894                 goto done;
895         }
896
897         for (i=0; i<r.count; i++) {
898                 (*set)[i].luid.low = r.set.set[i].luid.low;
899                 (*set)[i].luid.high = r.set.set[i].luid.high;
900                 (*set)[i].attr = r.set.set[i].attr;
901         }
902
903         *count=r.count;
904  done:
905
906         return result;
907 }
908
909 /** Get a privilege value given its name */
910
911 NTSTATUS rpccli_lsa_lookup_priv_value(struct rpc_pipe_client *cli, TALLOC_CTX *mem_ctx,
912                                  POLICY_HND *pol, const char *name, LUID *luid)
913 {
914         prs_struct qbuf, rbuf;
915         LSA_Q_LOOKUP_PRIV_VALUE q;
916         LSA_R_LOOKUP_PRIV_VALUE r;
917         NTSTATUS result;
918
919         ZERO_STRUCT(q);
920         ZERO_STRUCT(r);
921
922         /* Marshall data and send request */
923
924         init_lsa_q_lookup_priv_value(&q, pol, name);
925
926         CLI_DO_RPC( cli, mem_ctx, PI_LSARPC, LSA_LOOKUPPRIVVALUE,
927                 q, r,
928                 qbuf, rbuf,
929                 lsa_io_q_lookup_priv_value,
930                 lsa_io_r_lookup_priv_value,
931                 NT_STATUS_UNSUCCESSFUL);
932
933         result = r.status;
934
935         if (!NT_STATUS_IS_OK(result)) {
936                 goto done;
937         }
938
939         /* Return output parameters */
940
941         (*luid).low=r.luid.low;
942         (*luid).high=r.luid.high;
943
944  done:
945
946         return result;
947 }
948
949 /** Query LSA security object */
950
951 NTSTATUS rpccli_lsa_query_secobj(struct rpc_pipe_client *cli, TALLOC_CTX *mem_ctx,
952                               POLICY_HND *pol, uint32 sec_info, 
953                               SEC_DESC_BUF **psdb)
954 {
955         prs_struct qbuf, rbuf;
956         LSA_Q_QUERY_SEC_OBJ q;
957         LSA_R_QUERY_SEC_OBJ r;
958         NTSTATUS result;
959
960         ZERO_STRUCT(q);
961         ZERO_STRUCT(r);
962
963         /* Marshall data and send request */
964
965         init_q_query_sec_obj(&q, pol, sec_info);
966
967         CLI_DO_RPC( cli, mem_ctx, PI_LSARPC, LSA_QUERYSECOBJ,
968                 q, r,
969                 qbuf, rbuf,
970                 lsa_io_q_query_sec_obj,
971                 lsa_io_r_query_sec_obj,
972                 NT_STATUS_UNSUCCESSFUL);
973
974         result = r.status;
975
976         if (!NT_STATUS_IS_OK(result)) {
977                 goto done;
978         }
979
980         /* Return output parameters */
981
982         if (psdb)
983                 *psdb = r.buf;
984
985  done:
986
987         return result;
988 }
989
990
991 /* Enumerate account rights This is similar to enum_privileges but
992    takes a SID directly, avoiding the open_account call.
993 */
994
995 NTSTATUS rpccli_lsa_enum_account_rights(struct rpc_pipe_client *cli, TALLOC_CTX *mem_ctx,
996                                      POLICY_HND *pol, DOM_SID *sid,
997                                      uint32 *count, char ***priv_names)
998 {
999         prs_struct qbuf, rbuf;
1000         LSA_Q_ENUM_ACCT_RIGHTS q;
1001         LSA_R_ENUM_ACCT_RIGHTS r;
1002         NTSTATUS result;
1003         int i;
1004         fstring *privileges;
1005         char **names;
1006
1007         ZERO_STRUCT(q);
1008         ZERO_STRUCT(r);
1009
1010         /* Marshall data and send request */
1011         init_q_enum_acct_rights(&q, pol, 2, sid);
1012
1013         CLI_DO_RPC( cli, mem_ctx, PI_LSARPC, LSA_ENUMACCTRIGHTS,
1014                 q, r,
1015                 qbuf, rbuf,
1016                 lsa_io_q_enum_acct_rights,
1017                 lsa_io_r_enum_acct_rights,
1018                 NT_STATUS_UNSUCCESSFUL);
1019
1020         result = r.status;
1021
1022         if (!NT_STATUS_IS_OK(result)) {
1023                 goto done;
1024         }
1025
1026         *count = r.count;
1027         if (! *count) {
1028                 goto done;
1029         }
1030
1031         
1032         privileges = TALLOC_ARRAY( mem_ctx, fstring, *count );
1033         names      = TALLOC_ARRAY( mem_ctx, char *, *count );
1034
1035         for ( i=0; i<*count; i++ ) {
1036                 UNISTR4 *uni_string = &r.rights->strings[i];
1037
1038                 if ( !uni_string->string )
1039                         continue;
1040
1041                 rpcstr_pull( privileges[i], uni_string->string->buffer, sizeof(privileges[i]), -1, STR_TERMINATE );
1042                         
1043                 /* now copy to the return array */
1044                 names[i] = talloc_strdup( mem_ctx, privileges[i] );
1045         }
1046         
1047         *priv_names = names;
1048
1049 done:
1050
1051         return result;
1052 }
1053
1054
1055
1056 /* add account rights to an account. */
1057
1058 NTSTATUS rpccli_lsa_add_account_rights(struct rpc_pipe_client *cli, TALLOC_CTX *mem_ctx,
1059                                     POLICY_HND *pol, DOM_SID sid,
1060                                         uint32 count, const char **privs_name)
1061 {
1062         prs_struct qbuf, rbuf;
1063         LSA_Q_ADD_ACCT_RIGHTS q;
1064         LSA_R_ADD_ACCT_RIGHTS r;
1065         NTSTATUS result;
1066
1067         ZERO_STRUCT(q);
1068         ZERO_STRUCT(r);
1069
1070         /* Marshall data and send request */
1071         init_q_add_acct_rights(&q, pol, &sid, count, privs_name);
1072
1073         CLI_DO_RPC( cli, mem_ctx, PI_LSARPC, LSA_ADDACCTRIGHTS,
1074                 q, r,
1075                 qbuf, rbuf,
1076                 lsa_io_q_add_acct_rights,
1077                 lsa_io_r_add_acct_rights,
1078                 NT_STATUS_UNSUCCESSFUL);
1079
1080         result = r.status;
1081
1082         if (!NT_STATUS_IS_OK(result)) {
1083                 goto done;
1084         }
1085 done:
1086
1087         return result;
1088 }
1089
1090
1091 /* remove account rights for an account. */
1092
1093 NTSTATUS rpccli_lsa_remove_account_rights(struct rpc_pipe_client *cli, TALLOC_CTX *mem_ctx,
1094                                        POLICY_HND *pol, DOM_SID sid, BOOL removeall,
1095                                        uint32 count, const char **privs_name)
1096 {
1097         prs_struct qbuf, rbuf;
1098         LSA_Q_REMOVE_ACCT_RIGHTS q;
1099         LSA_R_REMOVE_ACCT_RIGHTS r;
1100         NTSTATUS result;
1101
1102         ZERO_STRUCT(q);
1103         ZERO_STRUCT(r);
1104
1105         /* Marshall data and send request */
1106         init_q_remove_acct_rights(&q, pol, &sid, removeall?1:0, count, privs_name);
1107
1108         CLI_DO_RPC( cli, mem_ctx, PI_LSARPC, LSA_REMOVEACCTRIGHTS,
1109                 q, r,
1110                 qbuf, rbuf,
1111                 lsa_io_q_remove_acct_rights,
1112                 lsa_io_r_remove_acct_rights,
1113                 NT_STATUS_UNSUCCESSFUL);
1114
1115         result = r.status;
1116
1117         if (!NT_STATUS_IS_OK(result)) {
1118                 goto done;
1119         }
1120 done:
1121
1122         return result;
1123 }
1124
1125
1126 #if 0
1127
1128 /** An example of how to use the routines in this file.  Fetch a DOMAIN
1129     sid. Does complete cli setup / teardown anonymously. */
1130
1131 BOOL fetch_domain_sid( char *domain, char *remote_machine, DOM_SID *psid)
1132 {
1133         extern pstring global_myname;
1134         struct cli_state cli;
1135         NTSTATUS result;
1136         POLICY_HND lsa_pol;
1137         BOOL ret = False;
1138  
1139         ZERO_STRUCT(cli);
1140         if(cli_initialise(&cli) == False) {
1141                 DEBUG(0,("fetch_domain_sid: unable to initialize client connection.\n"));
1142                 return False;
1143         }
1144  
1145         if(!resolve_name( remote_machine, &cli.dest_ip, 0x20)) {
1146                 DEBUG(0,("fetch_domain_sid: Can't resolve address for %s\n", remote_machine));
1147                 goto done;
1148         }
1149  
1150         if (!cli_connect(&cli, remote_machine, &cli.dest_ip)) {
1151                 DEBUG(0,("fetch_domain_sid: unable to connect to SMB server on \
1152 machine %s. Error was : %s.\n", remote_machine, cli_errstr(&cli) ));
1153                 goto done;
1154         }
1155
1156         if (!attempt_netbios_session_request(&cli, global_myname, remote_machine, &cli.dest_ip)) {
1157                 DEBUG(0,("fetch_domain_sid: machine %s rejected the NetBIOS session request.\n", 
1158                         remote_machine));
1159                 goto done;
1160         }
1161  
1162         cli.protocol = PROTOCOL_NT1;
1163  
1164         if (!cli_negprot(&cli)) {
1165                 DEBUG(0,("fetch_domain_sid: machine %s rejected the negotiate protocol. \
1166 Error was : %s.\n", remote_machine, cli_errstr(&cli) ));
1167                 goto done;
1168         }
1169  
1170         if (cli.protocol != PROTOCOL_NT1) {
1171                 DEBUG(0,("fetch_domain_sid: machine %s didn't negotiate NT protocol.\n",
1172                         remote_machine));
1173                 goto done;
1174         }
1175  
1176         /*
1177          * Do an anonymous session setup.
1178          */
1179  
1180         if (!cli_session_setup(&cli, "", "", 0, "", 0, "")) {
1181                 DEBUG(0,("fetch_domain_sid: machine %s rejected the session setup. \
1182 Error was : %s.\n", remote_machine, cli_errstr(&cli) ));
1183                 goto done;
1184         }
1185  
1186         if (!(cli.sec_mode & NEGOTIATE_SECURITY_USER_LEVEL)) {
1187                 DEBUG(0,("fetch_domain_sid: machine %s isn't in user level security mode\n",
1188                         remote_machine));
1189                 goto done;
1190         }
1191
1192         if (!cli_send_tconX(&cli, "IPC$", "IPC", "", 1)) {
1193                 DEBUG(0,("fetch_domain_sid: machine %s rejected the tconX on the IPC$ share. \
1194 Error was : %s.\n", remote_machine, cli_errstr(&cli) ));
1195                 goto done;
1196         }
1197
1198         /* Fetch domain sid */
1199  
1200         if (!cli_nt_session_open(&cli, PI_LSARPC)) {
1201                 DEBUG(0, ("fetch_domain_sid: Error connecting to SAM pipe\n"));
1202                 goto done;
1203         }
1204  
1205         result = cli_lsa_open_policy(&cli, cli.mem_ctx, True, SEC_RIGHTS_QUERY_VALUE, &lsa_pol);
1206         if (!NT_STATUS_IS_OK(result)) {
1207                 DEBUG(0, ("fetch_domain_sid: Error opening lsa policy handle. %s\n",
1208                         nt_errstr(result) ));
1209                 goto done;
1210         }
1211  
1212         result = cli_lsa_query_info_policy(&cli, cli.mem_ctx, &lsa_pol, 5, domain, psid);
1213         if (!NT_STATUS_IS_OK(result)) {
1214                 DEBUG(0, ("fetch_domain_sid: Error querying lsa policy handle. %s\n",
1215                         nt_errstr(result) ));
1216                 goto done;
1217         }
1218  
1219         ret = True;
1220
1221   done:
1222
1223         cli_shutdown(&cli);
1224         return ret;
1225 }
1226
1227 #endif
1228
1229 NTSTATUS rpccli_lsa_open_trusted_domain(struct rpc_pipe_client *cli, TALLOC_CTX *mem_ctx,
1230                                      POLICY_HND *pol, DOM_SID *dom_sid, uint32 access_mask,
1231                                      POLICY_HND *trustdom_pol)
1232 {
1233         prs_struct qbuf, rbuf;
1234         LSA_Q_OPEN_TRUSTED_DOMAIN q;
1235         LSA_R_OPEN_TRUSTED_DOMAIN r;
1236         NTSTATUS result;
1237
1238         ZERO_STRUCT(q);
1239         ZERO_STRUCT(r);
1240
1241         /* Initialise input parameters */
1242
1243         init_lsa_q_open_trusted_domain(&q, pol, dom_sid, access_mask);
1244
1245         /* Marshall data and send request */
1246
1247         CLI_DO_RPC( cli, mem_ctx, PI_LSARPC, LSA_OPENTRUSTDOM,
1248                 q, r,
1249                 qbuf, rbuf,
1250                 lsa_io_q_open_trusted_domain,
1251                 lsa_io_r_open_trusted_domain,
1252                 NT_STATUS_UNSUCCESSFUL);
1253
1254         /* Return output parameters */
1255         
1256         result = r.status;
1257
1258         if (NT_STATUS_IS_OK(result)) {
1259                 *trustdom_pol = r.handle;
1260         }
1261
1262         return result;
1263 }
1264
1265 NTSTATUS rpccli_lsa_query_trusted_domain_info(struct rpc_pipe_client *cli, TALLOC_CTX *mem_ctx,
1266                                            POLICY_HND *pol, 
1267                                            uint16 info_class, DOM_SID *dom_sid, 
1268                                            LSA_TRUSTED_DOMAIN_INFO **info)
1269 {
1270         prs_struct qbuf, rbuf;
1271         LSA_Q_QUERY_TRUSTED_DOMAIN_INFO q;
1272         LSA_R_QUERY_TRUSTED_DOMAIN_INFO r;
1273         NTSTATUS result = NT_STATUS_UNSUCCESSFUL;
1274
1275         ZERO_STRUCT(q);
1276         ZERO_STRUCT(r);
1277
1278         /* Marshall data and send request */
1279
1280         init_q_query_trusted_domain_info(&q, pol, info_class); 
1281
1282         CLI_DO_RPC( cli, mem_ctx, PI_LSARPC, LSA_QUERYTRUSTDOMINFO,
1283                 q, r,
1284                 qbuf, rbuf,
1285                 lsa_io_q_query_trusted_domain_info,
1286                 lsa_io_r_query_trusted_domain_info,
1287                 NT_STATUS_UNSUCCESSFUL);
1288
1289         result = r.status;
1290
1291         if (!NT_STATUS_IS_OK(result)) {
1292                 goto done;
1293         }
1294
1295         *info = r.info;
1296                 
1297 done:
1298         return result;
1299 }
1300
1301
1302 NTSTATUS rpccli_lsa_query_trusted_domain_info_by_sid(struct rpc_pipe_client *cli, TALLOC_CTX *mem_ctx,
1303                                                   POLICY_HND *pol, 
1304                                                   uint16 info_class, DOM_SID *dom_sid, 
1305                                                   LSA_TRUSTED_DOMAIN_INFO **info)
1306 {
1307         prs_struct qbuf, rbuf;
1308         LSA_Q_QUERY_TRUSTED_DOMAIN_INFO_BY_SID q;
1309         LSA_R_QUERY_TRUSTED_DOMAIN_INFO r;
1310         NTSTATUS result = NT_STATUS_UNSUCCESSFUL;
1311
1312         ZERO_STRUCT(q);
1313         ZERO_STRUCT(r);
1314
1315         /* Marshall data and send request */
1316
1317         init_q_query_trusted_domain_info_by_sid(&q, pol, info_class, dom_sid); 
1318
1319         CLI_DO_RPC( cli, mem_ctx, PI_LSARPC, LSA_QUERYTRUSTDOMINFOBYSID,
1320                 q, r,
1321                 qbuf, rbuf,
1322                 lsa_io_q_query_trusted_domain_info_by_sid,
1323                 lsa_io_r_query_trusted_domain_info,
1324                 NT_STATUS_UNSUCCESSFUL);
1325
1326         result = r.status;
1327
1328         if (!NT_STATUS_IS_OK(result)) {
1329                 goto done;
1330         }
1331
1332         *info = r.info;
1333
1334 done:
1335
1336         return result;
1337 }
1338
1339 NTSTATUS rpccli_lsa_query_trusted_domain_info_by_name(struct rpc_pipe_client *cli, TALLOC_CTX *mem_ctx,
1340                                                    POLICY_HND *pol, 
1341                                                    uint16 info_class, const char *domain_name, 
1342                                                    LSA_TRUSTED_DOMAIN_INFO **info)
1343 {
1344         prs_struct qbuf, rbuf;
1345         LSA_Q_QUERY_TRUSTED_DOMAIN_INFO_BY_NAME q;
1346         LSA_R_QUERY_TRUSTED_DOMAIN_INFO r;
1347         NTSTATUS result = NT_STATUS_UNSUCCESSFUL;
1348
1349         ZERO_STRUCT(q);
1350         ZERO_STRUCT(r);
1351
1352         /* Marshall data and send request */
1353
1354         init_q_query_trusted_domain_info_by_name(&q, pol, info_class, domain_name); 
1355
1356         CLI_DO_RPC( cli, mem_ctx, PI_LSARPC, LSA_QUERYTRUSTDOMINFOBYNAME,
1357                 q, r,
1358                 qbuf, rbuf,
1359                 lsa_io_q_query_trusted_domain_info_by_name,
1360                 lsa_io_r_query_trusted_domain_info,
1361                 NT_STATUS_UNSUCCESSFUL);
1362
1363         result = r.status;
1364
1365         if (!NT_STATUS_IS_OK(result)) {
1366                 goto done;
1367         }
1368
1369         *info = r.info;
1370
1371 done:
1372         
1373         return result;
1374 }