s3-registry: only include registry headers when really needed.
[kai/samba.git] / source3 / lib / util_reg_api.c
1 /*
2  * Unix SMB/CIFS implementation.
3  * Registry helper routines
4  * Copyright (C) Volker Lendecke 2006
5  * 
6  * This program is free software; you can redistribute it and/or modify it
7  * under the terms of the GNU General Public License as published by the Free
8  * Software Foundation; either version 3 of the License, or (at your option)
9  * any later version.
10  * 
11  * This program is distributed in the hope that it will be useful, but WITHOUT
12  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
13  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
14  * more details.
15  * 
16  * You should have received a copy of the GNU General Public License along with
17  * this program; if not, see <http://www.gnu.org/licenses/>.
18  */
19
20 #include "includes.h"
21 #include "registry.h"
22
23 #undef DBGC_CLASS
24 #define DBGC_CLASS DBGC_REGISTRY
25
26 WERROR registry_pull_value(TALLOC_CTX *mem_ctx,
27                            struct registry_value **pvalue,
28                            enum winreg_Type type, uint8 *data,
29                            uint32 size, uint32 length)
30 {
31         struct registry_value *value;
32         WERROR err;
33
34         if (!(value = TALLOC_ZERO_P(mem_ctx, struct registry_value))) {
35                 return WERR_NOMEM;
36         }
37
38         value->type = type;
39
40         switch (type) {
41         case REG_DWORD:
42                 if ((size != 4) || (length != 4)) {
43                         err = WERR_INVALID_PARAM;
44                         goto error;
45                 }
46                 value->v.dword = IVAL(data, 0);
47                 break;
48         case REG_SZ:
49         case REG_EXPAND_SZ:
50         {
51                 /*
52                  * Make sure we get a NULL terminated string for
53                  * convert_string_talloc().
54                  */
55
56                 smb_ucs2_t *tmp;
57
58                 if (length == 1) {
59                         /* win2k regedit gives us a string of 1 byte when
60                          * creating a new value of type REG_SZ. this workaround
61                          * replaces the input by using the same string as
62                          * winxp delivers. */
63                         length = 2;
64                         if (!(tmp = SMB_MALLOC_ARRAY(smb_ucs2_t, 2))) {
65                                 err = WERR_NOMEM;
66                                 goto error;
67                         }
68                         tmp[0] = 0;
69                         tmp[1] = 0;
70                         DEBUG(10, ("got REG_SZ value of length 1 - workaround "
71                                    "activated.\n"));
72                 }
73                 else if ((length % 2) != 0) {
74                         err = WERR_INVALID_PARAM;
75                         goto error;
76                 }
77                 else {
78                         uint32 num_ucs2 = length / 2;
79                         if (!(tmp = SMB_MALLOC_ARRAY(smb_ucs2_t, num_ucs2+1))) {
80                                 err = WERR_NOMEM;
81                                 goto error;
82                         }
83
84                         memcpy((void *)tmp, (const void *)data, length);
85                         tmp[num_ucs2] = 0;
86                 }
87
88                 if (length + 2 < length) {
89                         /* Integer wrap. */
90                         SAFE_FREE(tmp);
91                         err = WERR_INVALID_PARAM;
92                         goto error;
93                 }
94
95                 if (!convert_string_talloc(value, CH_UTF16LE, CH_UNIX, tmp,
96                                            length+2, (void *)&value->v.sz.str,
97                                            &value->v.sz.len, False)) {
98                         SAFE_FREE(tmp);
99                         err = WERR_INVALID_PARAM;
100                         goto error;
101                 }
102
103                 SAFE_FREE(tmp);
104                 break;
105         }
106         case REG_MULTI_SZ: {
107                 int i;
108                 const char **vals;
109                 DATA_BLOB blob;
110
111                 blob = data_blob_const(data, length);
112
113                 if (!pull_reg_multi_sz(mem_ctx, NULL, &blob, &vals)) {
114                         err = WERR_NOMEM;
115                         goto error;
116                 }
117
118                 for (i=0; vals[i]; i++) {
119                         ;;
120                 }
121
122                 value->v.multi_sz.num_strings = i;
123                 value->v.multi_sz.strings = (char **)vals;
124
125                 break;
126         }
127         case REG_BINARY:
128                 value->v.binary = data_blob_talloc(mem_ctx, data, length);
129                 break;
130         default:
131                 err = WERR_INVALID_PARAM;
132                 goto error;
133         }
134
135         *pvalue = value;
136         return WERR_OK;
137
138  error:
139         TALLOC_FREE(value);
140         return err;
141 }
142
143 WERROR registry_push_value(TALLOC_CTX *mem_ctx,
144                            const struct registry_value *value,
145                            DATA_BLOB *presult)
146 {
147         switch (value->type) {
148         case REG_DWORD: {
149                 char buf[4];
150                 SIVAL(buf, 0, value->v.dword);
151                 *presult = data_blob_talloc(mem_ctx, (void *)buf, 4);
152                 if (presult->data == NULL) {
153                         return WERR_NOMEM;
154                 }
155                 break;
156         }
157         case REG_SZ:
158         case REG_EXPAND_SZ: {
159                 if (!push_reg_sz(mem_ctx, NULL, presult, value->v.sz.str))
160                 {
161                         return WERR_NOMEM;
162                 }
163                 break;
164         }
165         case REG_MULTI_SZ: {
166                 /* handle the case where we don't get a NULL terminated array */
167                 const char **array;
168                 int i;
169
170                 array = talloc_array(mem_ctx, const char *,
171                                      value->v.multi_sz.num_strings + 1);
172                 if (!array) {
173                         return WERR_NOMEM;
174                 }
175
176                 for (i=0; i < value->v.multi_sz.num_strings; i++) {
177                         array[i] = value->v.multi_sz.strings[i];
178                 }
179                 array[i] = NULL;
180
181                 if (!push_reg_multi_sz(mem_ctx, NULL, presult, array)) {
182                         talloc_free(array);
183                         return WERR_NOMEM;
184                 }
185                 talloc_free(array);
186                 break;
187         }
188         case REG_BINARY:
189                 *presult = data_blob_talloc(mem_ctx,
190                                             value->v.binary.data,
191                                             value->v.binary.length);
192                 break;
193         default:
194                 return WERR_INVALID_PARAM;
195         }
196
197         return WERR_OK;
198 }