r16945: Sync trunk -> 3.0 for 3.0.24 code. Still need
[vlendec/samba-autobuild/.git] / source3 / libmsrpc / libmsrpc_internal.c
1 /* 
2  *  Unix SMB/CIFS implementation.
3  *  MS-RPC client internal functions
4  *  Copyright (C) Chris Nicholls              2005.
5  *  
6  *  This program is free software; you can redistribute it and/or modify
7  *  it under the terms of the GNU General Public License as published by
8  *  the Free Software Foundation; either version 2 of the License, or
9  *  (at your option) any later version.
10  *  
11  *  This program is distributed in the hope that it will be useful,
12  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
13  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14  *  GNU General Public License for more details.
15  *  
16  *  You should have received a copy of the GNU General Public License
17  *  along with this program; if not, write to the Free Software
18  *  Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
19  */
20
21
22 #include "libmsrpc.h"
23 #include "libmsrpc_internal.h"
24
25 /*used to get a struct rpc_pipe_client* to be passed into rpccli* calls*/
26 struct rpc_pipe_client *cac_GetPipe(CacServerHandle *hnd, int pi_idx)
27 {
28         SMBCSRV *srv = NULL;
29         struct rpc_pipe_client *pipe_hnd = NULL;
30
31         if(!hnd) {
32                 return NULL;
33         }
34
35         if(hnd->_internal.pipes[pi_idx] == False) {
36                 hnd->status = NT_STATUS_INVALID_HANDLE;
37                 return NULL;
38         }
39
40         srv = cac_GetServer(hnd);
41         if(!srv) {
42                 hnd->status = NT_STATUS_INVALID_CONNECTION;
43                 return NULL;
44         }
45
46         pipe_hnd = srv->cli->pipe_list;
47
48         while(pipe_hnd != NULL && pipe_hnd->pipe_idx != pi_idx) {
49                 pipe_hnd = pipe_hnd->next;
50         }
51
52         return pipe_hnd;
53 }
54
55 /*takes a string like HKEY_LOCAL_MACHINE\HARDWARE\ACPI and returns the reg_type code and then a pointer to the start of the path (HARDWARE)*/
56 int cac_ParseRegPath(char *path, uint32 *reg_type, char **key_name) {
57
58    if(!path)
59       return CAC_FAILURE;
60
61    if(strncmp(path, "HKLM", 4) == 0) {
62       *reg_type = HKEY_LOCAL_MACHINE;
63       *key_name = (path[4] == '\\') ? path + 5 : NULL;
64    }
65    else if(strncmp(path, "HKEY_LOCAL_MACHINE", 18) == 0) {
66       *reg_type = HKEY_LOCAL_MACHINE;
67       *key_name = (path[18] == '\\') ? path + 19 : NULL;
68    }
69    else if(strncmp(path, "HKCR", 4) == 0) {
70       *reg_type = HKEY_CLASSES_ROOT;
71       *key_name = (path[4] == '\\') ? path + 5 : NULL;
72    }
73    else if(strncmp(path, "HKEY_CLASSES_ROOT", 17) == 0) {
74       *reg_type = HKEY_CLASSES_ROOT;
75       *key_name = (path[17] == '\\') ? path + 18 : NULL;
76    }
77    else if(strncmp(path, "HKU", 3) == 0) {
78       *reg_type = HKEY_USERS;
79       *key_name = (path[3] == '\\') ? path + 4 : NULL;
80    }
81    else if(strncmp(path, "HKEY_USERS", 10) == 0) {
82       *reg_type = HKEY_USERS;
83       *key_name = (path[10] == '\\') ? path + 11 : NULL;
84    }
85    else if(strncmp(path, "HKPD", 4) == 0) {
86       *reg_type = HKEY_PERFORMANCE_DATA;
87       *key_name = (path[4] == '\\') ? path + 5 : NULL;
88    }
89    else if(strncmp(path, "HKEY_PERFORMANCE_DATA", 21) == 0) {
90       *reg_type = HKEY_PERFORMANCE_DATA;
91       *key_name = (path[21] == '\\') ? path + 22 : NULL;
92    }
93    else {
94       return CAC_FAILURE;
95    }
96
97    return CAC_SUCCESS;
98 }
99
100
101
102 RPC_DATA_BLOB *cac_MakeRpcDataBlob(TALLOC_CTX *mem_ctx, uint32 data_type, REG_VALUE_DATA data) {
103    RPC_DATA_BLOB *blob = NULL;
104    int i;
105    uint32 size = 0;
106    uint8 *multi = NULL;
107    uint32 multi_idx = 0;
108
109    blob = talloc(mem_ctx, RPC_DATA_BLOB);
110
111    if(!blob) {
112       errno = ENOMEM;
113       return NULL;
114    }
115
116    switch(data_type) {
117       case REG_SZ:
118          init_rpc_blob_str(blob, data.reg_sz, strlen(data.reg_sz ) + 1);
119          break;
120
121       case REG_EXPAND_SZ:
122          init_rpc_blob_str(blob, data.reg_expand_sz, strlen(data.reg_sz) + 1);
123          break;
124
125       case REG_BINARY:
126          init_rpc_blob_bytes(blob, data.reg_binary.data, data.reg_binary.data_length);
127          break;
128
129       case REG_DWORD:
130          init_rpc_blob_uint32(blob, data.reg_dword);
131          break;
132          
133       case REG_DWORD_BE:
134          init_rpc_blob_uint32(blob, data.reg_dword_be);
135          break;
136          
137       case REG_MULTI_SZ:
138          /*need to find the size*/
139          for(i = 0; i < data.reg_multi_sz.num_strings; i++) {
140             size += strlen(data.reg_multi_sz.strings[i]) + 1;
141          }
142
143          /**need a whole bunch of unicode strings in a row (seperated by null characters), with an extra null-character on the end*/
144
145          multi = TALLOC_ZERO_ARRAY(mem_ctx, uint8, (size + 1)*2); /*size +1 for the extra null character*/
146          if(!multi) {
147             errno = ENOMEM;
148             break;
149          }
150          
151          /*do it using rpcstr_push()*/
152          multi_idx = 0;
153          for(i = 0; i < data.reg_multi_sz.num_strings; i++) {
154             size_t len = strlen(data.reg_multi_sz.strings[i]) + 1;
155
156             rpcstr_push((multi + multi_idx), data.reg_multi_sz.strings[i], len * 2, STR_TERMINATE);
157
158             /* x2 becuase it is a uint8 buffer*/
159             multi_idx += len * 2;
160          }
161             
162          /*now initialize the buffer as binary data*/
163          init_rpc_blob_bytes(blob, multi, (size + 1)*2);
164
165          break;
166
167       default:
168          TALLOC_FREE(blob);
169          blob = NULL;
170          return NULL;
171    }
172
173    if(!(blob->buffer)) {
174       TALLOC_FREE(blob);
175       return NULL;
176    }
177
178    return blob;
179 }
180
181 /*turns a string in a uint16 array to a char array*/
182 char *cac_unistr_to_str(TALLOC_CTX *mem_ctx, uint16 *src, int num_bytes) {
183    char *buf;
184    
185    int i = 0;
186
187    uint32 str_len = 0;
188    
189    /*don't allocate more space than we need*/
190    while( (str_len) < num_bytes/2 && src[str_len] != 0x0000)
191       str_len++;
192
193    /*need room for a '\0'*/
194    str_len++;
195
196    buf = talloc_array(mem_ctx, char, str_len);
197    if(!buf) {
198       return NULL;
199    }
200
201    for(i = 0; i < num_bytes/2; i++) {
202       buf[i] = ((char *)src)[2*i];
203    }
204
205    buf[str_len - 1] = '\0';
206
207    return buf;
208 }
209
210 REG_VALUE_DATA *cac_MakeRegValueData(TALLOC_CTX *mem_ctx, uint32 data_type, REGVAL_BUFFER buf) {
211    REG_VALUE_DATA *data;
212
213    uint32 i;
214
215    /*all of the following used for MULTI_SZ data*/
216    uint32 size       = 0;
217    uint32 len        = 0;
218    uint32 multi_idx  = 0;
219    uint32 num_strings= 0;
220    char **strings    = NULL;
221
222    data = talloc(mem_ctx, REG_VALUE_DATA);
223    if(!data) {
224       errno = ENOMEM;
225       return NULL;
226    }
227
228    switch (data_type) {
229       case REG_SZ:
230          data->reg_sz = cac_unistr_to_str(mem_ctx, buf.buffer, buf.buf_len);
231          if(!data->reg_sz) {
232             TALLOC_FREE(data);
233             errno = ENOMEM;
234             data = NULL;
235          }
236             
237          break;
238
239       case REG_EXPAND_SZ:
240          data->reg_expand_sz = cac_unistr_to_str(mem_ctx, buf.buffer, buf.buf_len);
241
242          if(!data->reg_expand_sz) {
243             TALLOC_FREE(data);
244             errno = ENOMEM;
245             data = NULL;
246          }
247             
248          break;
249
250       case REG_BINARY:
251          size = buf.buf_len;
252
253          data->reg_binary.data_length = size;
254
255          data->reg_binary.data = talloc_memdup(mem_ctx, buf.buffer, size);
256          if(!data->reg_binary.data) {
257             TALLOC_FREE(data);
258             errno = ENOMEM;
259             data = NULL;
260          }
261          break;
262
263       case REG_DWORD:
264          data->reg_dword = *((uint32 *)buf.buffer);
265          break;
266
267       case REG_DWORD_BE:
268          data->reg_dword_be = *((uint32 *)buf.buffer);
269          break;
270
271       case REG_MULTI_SZ:
272          size = buf.buf_len;
273
274          /*find out how many strings there are. size is # of bytes and we want to work uint16*/
275          for(i = 0; i < (size/2 - 1); i++) {
276             if(buf.buffer[i] == 0x0000)
277                num_strings++;
278
279             /*buffer is suppsed to be terminated with \0\0, but it might not be*/
280             if(buf.buffer[i] == 0x0000 && buf.buffer[i + 1] == 0x0000)
281                break;
282          }
283          
284          strings = talloc_array(mem_ctx, char *, num_strings);
285          if(!strings) {
286             errno = ENOMEM;
287             TALLOC_FREE(data);
288             break;
289          }
290
291          if(num_strings == 0) /*then our work here is done*/
292             break;
293
294          for(i = 0; i < num_strings; i++) {
295             /*find out how many characters are in this string*/
296             len = 0;
297             /*make sure we don't go past the end of the buffer and keep looping until we have a uni \0*/
298             while( multi_idx + len < size/2 && buf.buffer[multi_idx + len] != 0x0000)
299                len++;
300
301             /*stay aware of the \0\0*/
302             len++;
303
304             strings[i] = TALLOC_ZERO_ARRAY(mem_ctx, char, len);
305
306             /*pull out the unicode string*/
307             rpcstr_pull(strings[i], (buf.buffer + multi_idx) , len, -1, STR_TERMINATE);
308
309             /*keep track of where we are in the bigger array*/
310             multi_idx += len;
311          }
312
313          data->reg_multi_sz.num_strings = num_strings;
314          data->reg_multi_sz.strings     = strings;
315
316          break;
317
318       default:
319          TALLOC_FREE(data);
320          data = NULL;
321    }
322
323    return data;
324 }
325
326 SAM_USERINFO_CTR *cac_MakeUserInfoCtr(TALLOC_CTX *mem_ctx, CacUserInfo *info) {
327    SAM_USERINFO_CTR *ctr = NULL;
328
329    /*the flags we are 'setting'- include/passdb.h*/
330    uint32 flags = ACCT_USERNAME | ACCT_FULL_NAME | ACCT_PRIMARY_GID | ACCT_DESCRIPTION | ACCT_COMMENT |
331                      ACCT_HOME_DIR | ACCT_HOME_DRIVE | ACCT_LOGON_SCRIPT | ACCT_PROFILE | ACCT_WORKSTATIONS |
332                       ACCT_FLAGS;
333
334    NTTIME logon_time;
335    NTTIME logoff_time;
336    NTTIME kickoff_time;
337    NTTIME pass_last_set_time;
338    NTTIME pass_can_change_time;
339    NTTIME pass_must_change_time;
340
341    UNISTR2 user_name;
342    UNISTR2 full_name;
343    UNISTR2 home_dir;
344    UNISTR2 dir_drive;
345    UNISTR2 log_scr;
346    UNISTR2 prof_path;
347    UNISTR2 desc;
348    UNISTR2 wkstas;
349    UNISTR2 mung_dial;
350    UNISTR2 unk;
351
352    ctr = talloc(mem_ctx, SAM_USERINFO_CTR);
353    if(!ctr)
354       return NULL;
355
356    ZERO_STRUCTP(ctr->info.id23);
357
358    ctr->info.id21 = talloc(mem_ctx, SAM_USER_INFO_21);
359    if(!ctr->info.id21)
360       return NULL;
361
362    ctr->switch_value = 21;
363
364    ZERO_STRUCTP(ctr->info.id21);
365
366    unix_to_nt_time(&logon_time, info->logon_time);
367    unix_to_nt_time(&logoff_time, info->logoff_time);
368    unix_to_nt_time(&kickoff_time, info->kickoff_time);
369    unix_to_nt_time(&pass_last_set_time, info->pass_last_set_time);
370    unix_to_nt_time(&pass_can_change_time, info->pass_can_change_time);
371    unix_to_nt_time(&pass_must_change_time, info->pass_must_change_time);
372
373    /*initialize the strings*/
374    init_unistr2(&user_name, info->username, UNI_STR_TERMINATE);
375    init_unistr2(&full_name, info->full_name, UNI_STR_TERMINATE);
376    init_unistr2(&home_dir, info->home_dir, UNI_STR_TERMINATE);
377    init_unistr2(&dir_drive, info->home_drive, UNI_STR_TERMINATE);
378    init_unistr2(&log_scr, info->logon_script, UNI_STR_TERMINATE);
379    init_unistr2(&prof_path, info->profile_path, UNI_STR_TERMINATE);
380    init_unistr2(&desc, info->description, UNI_STR_TERMINATE);
381    init_unistr2(&wkstas, info->workstations, UNI_STR_TERMINATE);
382    init_unistr2(&unk, "\0", UNI_STR_TERMINATE);
383    init_unistr2(&mung_dial, info->dial, UNI_STR_TERMINATE);
384
385    /*manually set passmustchange*/
386    ctr->info.id21->passmustchange = (info->pass_must_change) ? 0x01 : 0x00;
387
388    init_sam_user_info21W(ctr->info.id21,
389                          &logon_time,
390                          &logoff_time,
391                          &kickoff_time,
392                          &pass_last_set_time,
393                          &pass_can_change_time,
394                          &pass_must_change_time,
395                          &user_name,
396                          &full_name,
397                          &home_dir,
398                          &dir_drive,
399                          &log_scr,
400                          &prof_path,
401                          &desc,
402                          &wkstas,
403                          &unk,
404                          &mung_dial,
405                          info->lm_password,
406                          info->nt_password,
407                          info->rid,
408                          info->group_rid,
409                          info->acb_mask,
410                          flags,
411                          168, /*logon divs*/
412                          info->logon_hours,
413                          info->bad_passwd_count,
414                          info->logon_count);
415
416    return ctr;
417    
418 }
419
420 char *talloc_unistr2_to_ascii(TALLOC_CTX *mem_ctx, UNISTR2 str) {
421    char *buf = NULL;
422
423    if(!mem_ctx)
424       return NULL;
425
426    buf = talloc_array(mem_ctx, char, (str.uni_str_len + 1));
427    if(!buf)
428       return NULL;
429
430    unistr2_to_ascii(buf, &str, str.uni_str_len + 1);
431
432    return buf;
433 }
434
435 CacUserInfo *cac_MakeUserInfo(TALLOC_CTX *mem_ctx, SAM_USERINFO_CTR *ctr) {
436    CacUserInfo *info = NULL;
437    SAM_USER_INFO_21 *id21 = NULL;
438
439    if(!ctr || ctr->switch_value != 21)
440       return NULL;
441
442    info = talloc(mem_ctx, CacUserInfo);
443    if(!info)
444       return NULL;
445
446    id21 = ctr->info.id21;
447
448    ZERO_STRUCTP(info);
449
450    info->logon_time = nt_time_to_unix(&id21->logon_time);
451    info->logoff_time = nt_time_to_unix(&id21->logoff_time);
452    info->kickoff_time = nt_time_to_unix(&id21->kickoff_time);
453    info->pass_last_set_time = nt_time_to_unix(&id21->pass_last_set_time);
454    info->pass_can_change_time = nt_time_to_unix(&id21->pass_can_change_time);
455    info->pass_must_change_time = nt_time_to_unix(&id21->pass_must_change_time);
456
457    info->username = talloc_unistr2_to_ascii(mem_ctx, id21->uni_user_name);
458    if(!info->username)
459       return NULL;
460
461    info->full_name = talloc_unistr2_to_ascii(mem_ctx, id21->uni_full_name);
462    if(!info->full_name)
463       return NULL;
464    
465    info->home_dir = talloc_unistr2_to_ascii(mem_ctx, id21->uni_home_dir);
466    if(!info->home_dir)
467       return NULL;
468    
469    info->home_drive = talloc_unistr2_to_ascii(mem_ctx, id21->uni_dir_drive);
470    if(!info->home_drive)
471       return NULL;
472
473    info->logon_script = talloc_unistr2_to_ascii(mem_ctx, id21->uni_logon_script);
474    if(!info->logon_script)
475       return NULL;
476
477    info->profile_path = talloc_unistr2_to_ascii(mem_ctx, id21->uni_profile_path);
478    if(!info->profile_path)
479       return NULL;
480    
481    info->description = talloc_unistr2_to_ascii(mem_ctx, id21->uni_acct_desc);
482    if(!info->description)
483       return NULL;
484    
485    info->workstations = talloc_unistr2_to_ascii(mem_ctx, id21->uni_workstations);
486    if(!info->workstations)
487       return NULL;
488
489    info->dial = talloc_unistr2_to_ascii(mem_ctx, id21->uni_munged_dial);
490    if(!info->dial)
491       return NULL;
492
493    info->rid = id21->user_rid;
494    info->group_rid = id21->group_rid;
495    info->acb_mask = id21->acb_info;
496    info->bad_passwd_count = id21->bad_password_count;
497    info->logon_count = id21->logon_count;
498
499    memcpy(info->nt_password, id21->nt_pwd, 8);
500    memcpy(info->lm_password, id21->lm_pwd, 8);
501    
502    info->logon_hours = talloc_memdup(mem_ctx, &(id21->logon_hrs), sizeof(LOGON_HRS));
503    if(!info->logon_hours)
504       return NULL;
505
506    info->pass_must_change = (id21->passmustchange) ? True : False;
507
508    return info;
509 }
510
511 CacGroupInfo *cac_MakeGroupInfo(TALLOC_CTX *mem_ctx, GROUP_INFO_CTR *ctr) {
512    CacGroupInfo *info = NULL;
513
514    if(!mem_ctx || !ctr || ctr->switch_value1 != 1)
515       return NULL;
516
517    info = talloc(mem_ctx, CacGroupInfo);
518    if(!info)
519       return NULL;
520
521    info->name = talloc_unistr2_to_ascii(mem_ctx, ctr->group.info1.uni_acct_name);
522    if(!info->name)
523       return NULL;
524
525    info->description = talloc_unistr2_to_ascii(mem_ctx, ctr->group.info1.uni_acct_desc);
526    if(!info->description)
527       return NULL;
528
529    info->num_members = ctr->group.info1.num_members;
530
531    return info;
532 }
533
534 GROUP_INFO_CTR *cac_MakeGroupInfoCtr(TALLOC_CTX *mem_ctx, CacGroupInfo *info) {
535    GROUP_INFO_CTR *ctr = NULL;
536
537    if(!mem_ctx || !info)
538       return NULL;
539
540    ctr = talloc(mem_ctx, GROUP_INFO_CTR);
541    if(!ctr)
542       return NULL;
543
544    ctr->switch_value1 = 1;
545
546    init_samr_group_info1(&(ctr->group.info1), info->name, info->description, info->num_members);
547
548    return ctr;
549 }
550
551 CacAliasInfo *cac_MakeAliasInfo(TALLOC_CTX *mem_ctx, ALIAS_INFO_CTR ctr) {
552    CacGroupInfo *info = NULL;
553
554    if(!mem_ctx || ctr.level != 1)
555       return NULL;
556
557    info = talloc(mem_ctx, CacAliasInfo);
558    if(!info)
559       return NULL;
560
561    info->name = talloc_unistr2_to_ascii(mem_ctx, *(ctr.alias.info1.name.string));
562    if(!info->name)
563       return NULL;
564
565    info->description = talloc_unistr2_to_ascii(mem_ctx, *(ctr.alias.info1.description.string));
566    if(!info->name)
567       return NULL;
568
569    info->num_members = ctr.alias.info1.num_member;
570
571    return info;
572 }
573
574 ALIAS_INFO_CTR *cac_MakeAliasInfoCtr(TALLOC_CTX *mem_ctx, CacAliasInfo *info) {
575    ALIAS_INFO_CTR *ctr = NULL;
576
577    if(!mem_ctx || !info)
578       return NULL;
579
580    ctr = talloc(mem_ctx, ALIAS_INFO_CTR);
581    if(!ctr)
582       return NULL;
583
584    ctr->level = 1;
585
586    init_samr_alias_info1(&(ctr->alias.info1), info->name, info->num_members, info->description);
587
588    return ctr;
589 }
590
591 CacDomainInfo *cac_MakeDomainInfo(TALLOC_CTX *mem_ctx, SAM_UNK_INFO_1 *info1, SAM_UNK_INFO_2 *info2, SAM_UNK_INFO_12 *info12) {
592    CacDomainInfo *info = NULL;
593
594    if(!mem_ctx || !info1 || !info2 || !info12)
595       return NULL;
596
597    info = talloc(mem_ctx, CacDomainInfo);
598    if(!info)
599       return NULL;
600
601    info->min_pass_length = info1->min_length_password;
602    info->pass_history    = info1->password_history;
603
604    cac_InitCacTime(&(info->expire), info1->expire);
605    cac_InitCacTime(&(info->min_pass_age), info1->min_passwordage);
606
607    info->server_role       = info2->server_role;
608    info->num_users         = info2->num_domain_usrs;
609    info->num_domain_groups = info2->num_domain_grps;
610    info->num_local_groups  = info2->num_local_grps;
611
612    /*if these have been ZERO'd out we need to know. uni_str_len will be 0*/
613    if(info2->uni_comment.uni_str_len == 0) {
614       info->comment = talloc_strdup(mem_ctx, "\0");
615    }
616    else {
617       info->comment = talloc_unistr2_to_ascii(mem_ctx, info2->uni_comment);
618    }
619
620    if(info2->uni_domain.uni_str_len == 0) {
621       info->domain_name = talloc_strdup(mem_ctx, "\0");
622    }
623    else {
624       info->domain_name = talloc_unistr2_to_ascii(mem_ctx, info2->uni_domain);
625    }
626
627    if(info2->uni_server.uni_str_len == 0) {
628       info->server_name = talloc_strdup(mem_ctx, "\0");
629    }
630    else {
631       info->server_name = talloc_unistr2_to_ascii(mem_ctx, info2->uni_server);
632    }
633
634
635    cac_InitCacTime(&(info->lockout_duration), info12->duration);
636    cac_InitCacTime(&(info->lockout_reset), info12->reset_count);
637    info->num_bad_attempts = info12->bad_attempt_lockout;
638
639    return info;
640 }
641
642 char *cac_unistr_ascii(TALLOC_CTX *mem_ctx, UNISTR src) {
643    char *buf;
644    uint32 len;
645
646    if(!mem_ctx || !src.buffer)
647       return NULL;
648
649    len = unistrlen(src.buffer) + 1;
650
651    buf = TALLOC_ZERO_ARRAY(mem_ctx, char, len);
652    if(!buf)
653       return NULL;
654
655    rpcstr_pull(buf, src.buffer, len, -1, STR_TERMINATE);
656
657    return buf;
658 }
659
660 CacService *cac_MakeServiceArray(TALLOC_CTX *mem_ctx, ENUM_SERVICES_STATUS *svc, uint32 num_services) {
661    int i;
662    CacService *services = NULL;
663
664    if(!mem_ctx || !svc)
665       return NULL;
666
667    services = TALLOC_ZERO_ARRAY(mem_ctx, CacService, num_services);
668    if(!services)
669       return NULL;
670
671    for(i = 0; i < num_services; i++) {
672       services[i].service_name = cac_unistr_ascii(mem_ctx, svc[i].servicename);
673       services[i].display_name = cac_unistr_ascii(mem_ctx, svc[i].displayname);
674
675       if(!services[i].service_name || !services[i].display_name)
676          return NULL;
677
678       services[i].status = svc[i].status;
679    }
680
681    return services;
682 }
683
684 int cac_InitCacServiceConfig(TALLOC_CTX *mem_ctx, SERVICE_CONFIG *src, CacServiceConfig *dest) {
685    if(!src || !dest)
686       return CAC_FAILURE;
687
688    dest->exe_path = talloc_unistr2_to_ascii(mem_ctx, *src->executablepath);
689    if(!dest->exe_path)
690       return CAC_FAILURE;
691
692    dest->load_order_group = talloc_unistr2_to_ascii(mem_ctx, *src->loadordergroup);
693    if(!dest->load_order_group)
694       return CAC_FAILURE;
695
696    dest->dependencies = talloc_unistr2_to_ascii(mem_ctx, *src->dependencies);
697    if(!dest->dependencies)
698       return CAC_FAILURE;
699
700    dest->start_name = talloc_unistr2_to_ascii(mem_ctx, *src->startname);
701    if(!dest->start_name)
702       return CAC_FAILURE;
703
704    dest->display_name = talloc_unistr2_to_ascii(mem_ctx, *src->displayname);
705    if(!dest->display_name)
706       return CAC_FAILURE;
707
708    dest->type = src->service_type;
709    dest->start_type = src->start_type;
710    dest->error_control = src->error_control;
711    dest->tag_id = src->tag_id;
712
713    return CAC_SUCCESS;
714 }