s3:registry: extract registry_pull/push_value prototypes into own header
[amitay/samba.git] / source3 / registry / reg_util_marshalling.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 #include "reg_util_marshalling.h"
23
24 #undef DBGC_CLASS
25 #define DBGC_CLASS DBGC_REGISTRY
26
27 WERROR registry_pull_value(TALLOC_CTX *mem_ctx,
28                            struct registry_value **pvalue,
29                            enum winreg_Type type, uint8 *data,
30                            uint32 size, uint32 length)
31 {
32         struct registry_value *value;
33         WERROR err;
34
35         if (!(value = TALLOC_ZERO_P(mem_ctx, struct registry_value))) {
36                 return WERR_NOMEM;
37         }
38
39         value->type = type;
40
41         switch (type) {
42         case REG_DWORD:
43         case REG_DWORD_BIG_ENDIAN:
44                 if ((size != 4) || (length != 4)) {
45                         err = WERR_INVALID_PARAM;
46                         goto error;
47                 }
48                 value->v.dword = IVAL(data, 0);
49                 break;
50         case REG_QWORD:
51                 if ((size != 8) || (length != 8)) {
52                         err = WERR_INVALID_PARAM;
53                         goto error;
54                 }
55                 value->v.qword = BVAL(data, 0);
56                 break;
57         case REG_SZ:
58         case REG_EXPAND_SZ:
59         {
60                 /*
61                  * Make sure we get a NULL terminated string for
62                  * convert_string_talloc().
63                  */
64
65                 smb_ucs2_t *tmp;
66
67                 if (length == 1) {
68                         /* win2k regedit gives us a string of 1 byte when
69                          * creating a new value of type REG_SZ. this workaround
70                          * replaces the input by using the same string as
71                          * winxp delivers. */
72                         length = 2;
73                         if (!(tmp = SMB_MALLOC_ARRAY(smb_ucs2_t, 2))) {
74                                 err = WERR_NOMEM;
75                                 goto error;
76                         }
77                         tmp[0] = 0;
78                         tmp[1] = 0;
79                         DEBUG(10, ("got REG_SZ value of length 1 - workaround "
80                                    "activated.\n"));
81                 }
82                 else if ((length % 2) != 0) {
83                         err = WERR_INVALID_PARAM;
84                         goto error;
85                 }
86                 else {
87                         uint32 num_ucs2 = length / 2;
88                         if (!(tmp = SMB_MALLOC_ARRAY(smb_ucs2_t, num_ucs2+1))) {
89                                 err = WERR_NOMEM;
90                                 goto error;
91                         }
92
93                         memcpy((void *)tmp, (const void *)data, length);
94                         tmp[num_ucs2] = 0;
95                 }
96                 if (length + 2 < length) {
97                         /* Integer wrap. */
98                         SAFE_FREE(tmp);
99                         err = WERR_INVALID_PARAM;
100                         goto error;
101                 }
102
103                 if (!convert_string_talloc(value, CH_UTF16LE, CH_UNIX, tmp,
104                                            length+2, (void *)&value->v.sz.str,
105                                            &value->v.sz.len, False)) {
106                         SAFE_FREE(tmp);
107                         err = WERR_INVALID_PARAM;
108                         goto error;
109                 }
110
111                 SAFE_FREE(tmp);
112                 break;
113         }
114         case REG_MULTI_SZ: {
115                 int i;
116                 const char **vals;
117                 DATA_BLOB blob;
118
119                 blob = data_blob_const(data, length);
120
121                 if (!pull_reg_multi_sz(mem_ctx, &blob, &vals)) {
122                         err = WERR_NOMEM;
123                         goto error;
124                 }
125
126                 for (i=0; vals[i]; i++) {
127                         ;;
128                 }
129
130                 value->v.multi_sz.num_strings = i;
131                 value->v.multi_sz.strings = (char **)vals;
132
133                 break;
134         }
135         case REG_BINARY:
136                 value->v.binary = data_blob_talloc(mem_ctx, data, length);
137                 break;
138         default:
139                 err = WERR_INVALID_PARAM;
140                 goto error;
141         }
142
143         *pvalue = value;
144         return WERR_OK;
145
146  error:
147         TALLOC_FREE(value);
148         return err;
149 }
150
151 WERROR registry_push_value(TALLOC_CTX *mem_ctx,
152                            const struct registry_value *value,
153                            DATA_BLOB *presult)
154 {
155         switch (value->type) {
156         case REG_DWORD:
157         case REG_DWORD_BIG_ENDIAN: {
158                 char buf[4];
159                 SIVAL(buf, 0, value->v.dword);
160                 *presult = data_blob_talloc(mem_ctx, (void *)buf, 4);
161                 if (presult->data == NULL) {
162                         return WERR_NOMEM;
163                 }
164                 break;
165         }
166         case REG_QWORD: {
167                 char buf[8];
168                 SBVAL(buf, 0, value->v.qword);
169                 *presult = data_blob_talloc(mem_ctx, (void *)buf, 8);
170                 if (presult->data == NULL) {
171                         return WERR_NOMEM;
172                 }
173                 break;
174         }
175         case REG_SZ:
176         case REG_EXPAND_SZ: {
177                 if (!push_reg_sz(mem_ctx, presult, value->v.sz.str))
178                 {
179                         return WERR_NOMEM;
180                 }
181                 break;
182         }
183         case REG_MULTI_SZ: {
184                 /* handle the case where we don't get a NULL terminated array */
185                 const char **array;
186                 int i;
187
188                 array = talloc_array(mem_ctx, const char *,
189                                      value->v.multi_sz.num_strings + 1);
190                 if (!array) {
191                         return WERR_NOMEM;
192                 }
193
194                 for (i=0; i < value->v.multi_sz.num_strings; i++) {
195                         array[i] = value->v.multi_sz.strings[i];
196                 }
197                 array[i] = NULL;
198
199                 if (!push_reg_multi_sz(mem_ctx, presult, array)) {
200                         talloc_free(array);
201                         return WERR_NOMEM;
202                 }
203                 talloc_free(array);
204                 break;
205         }
206         case REG_BINARY:
207                 *presult = data_blob_talloc(mem_ctx,
208                                             value->v.binary.data,
209                                             value->v.binary.length);
210                 break;
211         default:
212                 return WERR_INVALID_PARAM;
213         }
214
215         return WERR_OK;
216 }