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