1 /*
2     OWFS -- One-Wire filesystem
3     OWHTTPD -- One-Wire Web Server
4     Written 2003 Paul H Alfille
5     email: paul.alfille@gmail.com
6     Released under the GPL
7     See the header file: ow.h for full attribution
8     1wire/iButton system from Dallas Semiconductor
9 */
10 
11 /* General Device File format:
12     This device file corresponds to a specific 1wire/iButton chip type
13     ( or a closely related family of chips )
14 
15     The connection to the larger program is through the "device" data structure,
16       which must be declared in the acompanying header file.
17 
18     The device structure holds the
19       family code,
20       name,
21       device type (chip, interface or pseudo)
22       number of properties,
23       list of property structures, called "filetype".
24 
25     Each filetype structure holds the
26       name,
27       estimated length (in bytes),
28       aggregate structure pointer,
29       data format,
30       read function,
31       write funtion,
32       generic data pointer
33 
34     The aggregate structure, is present for properties that several members
35     (e.g. pages of memory or entries in a temperature log. It holds:
36       number of elements
37       whether the members are lettered or numbered
38       whether the elements are stored together and split, or separately and joined
39 */
40 
41 #include <config.h>
42 #include "owfs_config.h"
43 #include "ow_1991.h"
44 
45 /* ------- Prototypes ----------- */
46 
47 WRITE_FUNCTION(FS_password);
48 WRITE_FUNCTION(FS_reset);
49 READ_FUNCTION(FS_r_subkey);
50 WRITE_FUNCTION(FS_w_subkey);
51 READ_FUNCTION(FS_r_id);
52 WRITE_FUNCTION(FS_w_id);
53 
54 #define _DS1991_PAGES	3
55 #define _DS1991_PAGE_LENGTH 0x40
56 
57 #define _DS1991_ID_START   0x00
58 #define _DS1991_ID_LENGTH   8
59 
60 #define _DS1991_PASSWORD_START   (_DS1991_ID_START + _DS1991_ID_LENGTH )
61 #define _DS1991_PASSWORD_LENGTH   8
62 
63 #define _DS1991_DATA_START   ( _DS1991_PASSWORD_START + _DS1991_PASSWORD_LENGTH )
64 #define _DS1991_DATA_LENGTH   (_DS1991_PAGE_LENGTH - _DS1991_DATA_START)
65 
66 
67 BYTE subkey_byte[3] = { (0<<6), (1<<6), (2<<6), } ;
68 
69 
70 /* ------- Structures ----------- */
71 
72 static struct aggregate A1991_password = { 0, ag_letters, ag_sparse, };
73 static struct filetype DS1991[] = {
74 	F_STANDARD,
75 
76 	{"subkey0", PROPERTY_LENGTH_SUBDIR, NON_AGGREGATE, ft_subdir, fc_subdir, NO_READ_FUNCTION, NO_WRITE_FUNCTION, VISIBLE, NO_FILETYPE_DATA, },
77 	{"subkey0/password", _DS1991_ID_LENGTH, &A1991_password, ft_binary, fc_stable, NO_READ_FUNCTION, FS_password, VISIBLE,  {.i=0,}, },
78 	{"subkey0/reset", PROPERTY_LENGTH_YESNO, &A1991_password, ft_yesno, fc_stable, NO_READ_FUNCTION, FS_reset, VISIBLE,  {.i=0,}, },
79 	{"subkey0/secure_data", _DS1991_DATA_LENGTH, &A1991_password, ft_binary, fc_stable, FS_r_subkey, FS_w_subkey, VISIBLE,  {.i=0,}, },
80 	{"subkey0/id", _DS1991_ID_LENGTH, &A1991_password, ft_binary, fc_stable, FS_r_id, FS_w_id, VISIBLE,  {.i=0,}, },
81 
82 	{"subkey1", PROPERTY_LENGTH_SUBDIR, NON_AGGREGATE, ft_subdir, fc_subdir, NO_READ_FUNCTION, NO_WRITE_FUNCTION, VISIBLE, NO_FILETYPE_DATA, },
83 	{"subkey1/password", _DS1991_ID_LENGTH, &A1991_password, ft_binary, fc_stable, NO_READ_FUNCTION, FS_password, VISIBLE,  {.i=1,}, },
84 	{"subkey1/reset", PROPERTY_LENGTH_YESNO, &A1991_password, ft_yesno, fc_stable, NO_READ_FUNCTION, FS_reset, VISIBLE,  {.i=1,}, },
85 	{"subkey1/secure_data", _DS1991_DATA_LENGTH, &A1991_password, ft_binary, fc_stable, FS_r_subkey, FS_w_subkey, VISIBLE,  {.i=1,}, },
86 	{"subkey1/id", _DS1991_ID_LENGTH, &A1991_password, ft_binary, fc_stable, FS_r_id, FS_w_id, VISIBLE,  {.i=1,}, },
87 
88 	{"subkey2", PROPERTY_LENGTH_SUBDIR, NON_AGGREGATE, ft_subdir, fc_subdir, NO_READ_FUNCTION, NO_WRITE_FUNCTION, VISIBLE, NO_FILETYPE_DATA, },
89 	{"subkey2/password", _DS1991_ID_LENGTH, &A1991_password, ft_binary, fc_stable, NO_READ_FUNCTION, FS_password, VISIBLE,  {.i=2,}, },
90 	{"subkey2/reset", PROPERTY_LENGTH_YESNO, &A1991_password, ft_yesno, fc_stable, NO_READ_FUNCTION, FS_reset, VISIBLE,  {.i=2,}, },
91 	{"subkey2/secure_data", _DS1991_DATA_LENGTH, &A1991_password, ft_binary, fc_stable, FS_r_subkey, FS_w_subkey, VISIBLE,  {.i=2,}, },
92 	{"subkey2/id", _DS1991_ID_LENGTH, &A1991_password, ft_binary, fc_stable, FS_r_id, FS_w_id, VISIBLE,  {.i=2,}, },
93 };
94 
95 DeviceEntry(02, DS1991, NO_GENERIC_READ, NO_GENERIC_WRITE);
96 
97 static struct filetype DS1425[] = {
98 	F_STANDARD,
99 
100 	{"subkey0", PROPERTY_LENGTH_SUBDIR, NON_AGGREGATE, ft_subdir, fc_subdir, NO_READ_FUNCTION, NO_WRITE_FUNCTION, VISIBLE, NO_FILETYPE_DATA, },
101 	{"subkey0/password", _DS1991_ID_LENGTH, &A1991_password, ft_binary, fc_stable, NO_READ_FUNCTION, FS_password, VISIBLE,  {.i=0,}, },
102 	{"subkey0/reset", PROPERTY_LENGTH_YESNO, &A1991_password, ft_yesno, fc_stable, NO_READ_FUNCTION, FS_reset, VISIBLE,  {.i=0,}, },
103 	{"subkey0/secure_data", _DS1991_DATA_LENGTH, &A1991_password, ft_binary, fc_stable, FS_r_subkey, FS_w_subkey, VISIBLE,  {.i=0,}, },
104 	{"subkey0/id", _DS1991_ID_LENGTH, &A1991_password, ft_binary, fc_stable, FS_r_id, FS_w_id, VISIBLE,  {.i=0,}, },
105 
106 	{"subkey1", PROPERTY_LENGTH_SUBDIR, NON_AGGREGATE, ft_subdir, fc_subdir, NO_READ_FUNCTION, NO_WRITE_FUNCTION, VISIBLE, NO_FILETYPE_DATA, },
107 	{"subkey1/password", _DS1991_ID_LENGTH, &A1991_password, ft_binary, fc_stable, NO_READ_FUNCTION, FS_password, VISIBLE,  {.i=1,}, },
108 	{"subkey1/reset", PROPERTY_LENGTH_YESNO, &A1991_password, ft_yesno, fc_stable, NO_READ_FUNCTION, FS_reset, VISIBLE,  {.i=1,}, },
109 	{"subkey1/secure_data", _DS1991_DATA_LENGTH, &A1991_password, ft_binary, fc_stable, FS_r_subkey, FS_w_subkey, VISIBLE,  {.i=1,}, },
110 	{"subkey1/id", _DS1991_ID_LENGTH, &A1991_password, ft_binary, fc_stable, FS_r_id, FS_w_id, VISIBLE,  {.i=1,}, },
111 
112 	{"subkey2", PROPERTY_LENGTH_SUBDIR, NON_AGGREGATE, ft_subdir, fc_subdir, NO_READ_FUNCTION, NO_WRITE_FUNCTION, VISIBLE, NO_FILETYPE_DATA, },
113 	{"subkey2/password", _DS1991_ID_LENGTH, &A1991_password, ft_binary, fc_stable, NO_READ_FUNCTION, FS_password, VISIBLE,  {.i=2,}, },
114 	{"subkey2/reset", PROPERTY_LENGTH_YESNO, &A1991_password, ft_yesno, fc_stable, NO_READ_FUNCTION, FS_reset, VISIBLE,  {.i=2,}, },
115 	{"subkey2/secure_data", _DS1991_DATA_LENGTH, &A1991_password, ft_binary, fc_stable, FS_r_subkey, FS_w_subkey, VISIBLE,  {.i=2,}, },
116 	{"subkey2/id", _DS1991_ID_LENGTH, &A1991_password, ft_binary, fc_stable, FS_r_id, FS_w_id, VISIBLE,  {.i=2,}, },
117 };
118 
119 DeviceEntry(82, DS1425, NO_GENERIC_READ, NO_GENERIC_WRITE);
120 
121 #define _1W_WRITE_SCRATCHPAD 0x96
122 #define _1W_READ_SCRATCHPAD 0x69
123 #define _1W_COPY_SCRATCHPAD 0x3C
124 #define _1W_WRITE_PASSWORD 0x5A
125 #define _1W_WRITE_SUBKEY 0x99
126 #define _1W_READ_SUBKEY 0x66
127 
128 /* ------- Functions ------------ */
129 
130 
131 static GOOD_OR_BAD OW_password( int subkey, const BYTE * new_id, const BYTE * new_password, const struct parsedname * pn ) ;
132 static GOOD_OR_BAD OW_read_subkey( int subkey, BYTE * password, size_t size, off_t offset, BYTE * data, const struct parsedname * pn ) ;
133 static GOOD_OR_BAD OW_write_subkey( int subkey, BYTE * password, size_t size, off_t offset, BYTE * data, const struct parsedname * pn ) ;
134 static GOOD_OR_BAD OW_read_id( int subkey, BYTE * id, const struct parsedname * pn ) ;
135 static GOOD_OR_BAD OW_write_id( int subkey, BYTE * password, BYTE * id, const struct parsedname * pn ) ;
136 static GOOD_OR_BAD OW_write_password( int subkey, BYTE * old_password, BYTE * new_password, const struct parsedname * pn ) ;
137 
138 static GOOD_OR_BAD ToPassword( char * text, BYTE * psw ) ;
139 
140 
141 /* array with magic bytes representing the Copy Scratch operations */
142 enum block { block_ALL = 0, block_IDENT, block_PASSWORD, block_DATA };
143 #define _DS1991_COPY_BLOCK_LENGTH	8
144 #define _DS1991_COPY_BLOCK_ITEMS	9
145 
146 static const BYTE cp_array[_DS1991_COPY_BLOCK_ITEMS][_DS1991_COPY_BLOCK_LENGTH] = {
147 	{0x56, 0x56, 0x7F, 0x51, 0x57, 0x5D, 0x5A, 0x7F},	// 00-3F
148 	{0x9A, 0x9A, 0xB3, 0x9D, 0x64, 0x6E, 0x69, 0x4C},	// ident
149 	{0x9A, 0x9A, 0x4C, 0x62, 0x9B, 0x91, 0x69, 0x4C},	// passwd
150 	{0x9A, 0x65, 0xB3, 0x62, 0x9B, 0x6E, 0x96, 0x4C},	// 10-17
151 	{0x6A, 0x6A, 0x43, 0x6D, 0x6B, 0x61, 0x66, 0x43},	// 18-1F
152 	{0x95, 0x95, 0xBC, 0x92, 0x94, 0x9E, 0x99, 0xBC},	// 20-27
153 	{0x65, 0x9A, 0x4C, 0x9D, 0x64, 0x91, 0x69, 0xB3},	// 28-2F
154 	{0x65, 0x65, 0xB3, 0x9D, 0x64, 0x6E, 0x96, 0xB3},	// 30-37
155 	{0x65, 0x65, 0x4C, 0x62, 0x9B, 0x91, 0x96, 0xB3},	// 38-3F
156 };
157 
158 #ifndef MIN
159 #define MIN(a, b) ((a) < (b) ? (a) : (b))
160 #endif
161 
162 // reset the subkey area with a new password
163 // clear all data
164 // put default ID in it.
FS_reset(struct one_wire_query * owq)165 static ZERO_OR_ERROR FS_reset(struct one_wire_query *owq)
166 {
167 	struct parsedname *pn = PN(owq);
168 	int subkey = pn->selected_filetype->data.i ;
169 	BYTE new_password[_DS1991_PASSWORD_LENGTH] ;
170 	BYTE new_id[_DS1991_PASSWORD_LENGTH + 1 ] ;
171 
172 	if ( OWQ_Y(owq) == 0 ) {
173 		// Not true request
174 		return 0 ;
175 	}
176 
177 	if ( BAD(ToPassword( pn->sparse_name, new_password ) ) ) {
178 		return -EINVAL ;
179 	}
180 
181 	snprintf( (char *) new_id, _DS1991_ID_LENGTH + 1, "Subkey %.1d", subkey  ) ;
182 
183 	return GB_to_Z_OR_E(OW_password(subkey, new_id, new_password, pn)) ;
184 }
185 
186 // write a new password without clearing data
187 // done with a scratchpad copy
FS_password(struct one_wire_query * owq)188 static ZERO_OR_ERROR FS_password(struct one_wire_query *owq)
189 {
190 	struct parsedname *pn = PN(owq);
191 	int subkey = pn->selected_filetype->data.i ;
192 	BYTE new_password[_DS1991_PASSWORD_LENGTH] ;
193 	BYTE old_password[_DS1991_PASSWORD_LENGTH] ;
194 
195 	if ( OWQ_offset(owq) != 0 ) {
196 		return -EINVAL ;
197 	}
198 
199 	if ( OWQ_size(owq) != _DS1991_PASSWORD_LENGTH ) {
200 		return -EINVAL ;
201 	}
202 
203 	memcpy( new_password, (BYTE *)OWQ_buffer(owq) , _DS1991_PASSWORD_LENGTH ) ;
204 	if ( BAD(ToPassword( pn->sparse_name, old_password ) ) ) {
205 		return -EINVAL ;
206 	}
207 
208 	return GB_to_Z_OR_E(OW_write_password(subkey, old_password, new_password, pn)) ;
209 }
210 
211 // write to secure data area
212 // needs the password encoded in the extension
FS_w_subkey(struct one_wire_query * owq)213 static ZERO_OR_ERROR FS_w_subkey(struct one_wire_query *owq)
214 {
215 	struct parsedname *pn = PN(owq);
216 	int subkey = pn->selected_filetype->data.i ;
217 	BYTE password[_DS1991_PASSWORD_LENGTH] ;
218 
219 	if ( BAD(ToPassword( pn->sparse_name, password ) ) ) {
220 		return -EINVAL ;
221 	}
222 
223 	if ( BAD (OW_write_subkey( subkey, password, OWQ_size(owq), OWQ_offset(owq)+_DS1991_DATA_START, (BYTE *) OWQ_buffer(owq), pn )) ) {
224 		return -EINVAL ;
225 	}
226 
227 	return 0 ;
228 }
229 
230 // read from secure data area
231 // needs the password encoded in the extension
FS_r_subkey(struct one_wire_query * owq)232 static ZERO_OR_ERROR FS_r_subkey(struct one_wire_query *owq)
233 {
234 	struct parsedname *pn = PN(owq);
235 	int subkey = pn->selected_filetype->data.i ;
236 	BYTE password[_DS1991_PASSWORD_LENGTH] ;
237 
238 	if ( BAD(ToPassword( pn->sparse_name, password ) ) ) {
239 		return -EINVAL ;
240 	}
241 
242 	if ( BAD (OW_read_subkey( subkey, password, OWQ_size(owq), OWQ_offset(owq)+_DS1991_DATA_START, (BYTE *) OWQ_buffer(owq), pn )) ) {
243 		return -EINVAL ;
244 	}
245 	OWQ_length(owq) = OWQ_size(owq) ;
246 
247 	return 0 ;
248 }
249 
250 // read id
251 // needs a dummy password encoded in the extension
FS_r_id(struct one_wire_query * owq)252 static ZERO_OR_ERROR FS_r_id(struct one_wire_query *owq)
253 {
254 	struct parsedname *pn = PN(owq);
255 	int subkey = pn->selected_filetype->data.i ;
256 	BYTE id[_DS1991_ID_LENGTH] ;
257 
258 	if ( BAD (OW_read_id( subkey, id, pn )) ) {
259 		return -EINVAL ;
260 	}
261 
262 	return OWQ_format_output_offset_and_size( (const char *) id, _DS1991_ID_LENGTH, owq ) ;
263 }
264 
265 // write new id
266 // needs the password encoded in the extension
FS_w_id(struct one_wire_query * owq)267 static ZERO_OR_ERROR FS_w_id(struct one_wire_query *owq)
268 {
269 	struct parsedname *pn = PN(owq);
270 	int subkey = pn->selected_filetype->data.i ;
271 	BYTE password[_DS1991_PASSWORD_LENGTH] ;
272 	BYTE id[_DS1991_ID_LENGTH] ;
273 
274 	if ( BAD(ToPassword( pn->sparse_name, password ) ) ) {
275 		return -EINVAL ;
276 	}
277 
278 	if ( OWQ_offset(owq) != 0 && OWQ_size(owq) != _DS1991_ID_LENGTH ) {
279 		// Fill id  with existing id
280 		if ( BAD (OW_read_id( subkey, id, pn )) ) {
281 			return -EINVAL ;
282 		}
283 	}
284 
285 	memcpy( &id[OWQ_offset(owq)], OWQ_buffer(owq), OWQ_size(owq) ) ;
286 
287 	if ( BAD (OW_write_id( subkey, password, id, pn )) ) {
288 		return -EINVAL ;
289 	}
290 
291 	return 0 ;
292 }
293 
OW_password(int subkey,const BYTE * new_id,const BYTE * new_password,const struct parsedname * pn)294 static GOOD_OR_BAD OW_password( int subkey, const BYTE * new_id, const BYTE * new_password, const struct parsedname * pn )
295 {
296 	BYTE subkey_addr = subkey_byte[ subkey ] ;
297 	BYTE write_pwd[] = { _1W_WRITE_PASSWORD, subkey_addr, BYTE_INVERSE(subkey_addr), } ;
298 	BYTE old_id[_DS1991_ID_LENGTH] ;
299 	struct transaction_log t[] = {
300 		TRXN_START,
301 		TRXN_WRITE3(write_pwd),
302 		TRXN_READ(old_id, _DS1991_ID_LENGTH),
303 		TRXN_WRITE(old_id, _DS1991_ID_LENGTH),
304 		TRXN_WRITE(new_id, _DS1991_ID_LENGTH),
305 		TRXN_WRITE(new_password, _DS1991_PASSWORD_LENGTH),
306 		TRXN_END,
307 	};
308 
309 	return BUS_transaction(t, pn) ;
310 }
311 
312 
OW_read_id(int subkey,BYTE * id,const struct parsedname * pn)313 static GOOD_OR_BAD OW_read_id( int subkey, BYTE * id, const struct parsedname * pn )
314 {
315 	BYTE subkey_addr = subkey_byte[ subkey ] + _DS1991_DATA_START ;
316 	BYTE read_sbk[] = { _1W_READ_SUBKEY, subkey_addr, BYTE_INVERSE(subkey_addr), } ;
317 	struct transaction_log t[] = {
318 		TRXN_START,
319 		TRXN_WRITE3(read_sbk),
320 		TRXN_READ(id, _DS1991_ID_LENGTH),
321 		TRXN_END,
322 	};
323 
324 	return BUS_transaction(t, pn) ;
325 }
326 
OW_read_subkey(int subkey,BYTE * password,size_t size,off_t offset,BYTE * data,const struct parsedname * pn)327 static GOOD_OR_BAD OW_read_subkey( int subkey, BYTE * password, size_t size, off_t offset, BYTE * data, const struct parsedname * pn )
328 {
329 	BYTE subkey_addr = subkey_byte[ subkey ] + offset ;
330 	BYTE write_sbk[] = { _1W_READ_SUBKEY, subkey_addr, BYTE_INVERSE(subkey_addr), } ;
331 	BYTE old_id[_DS1991_ID_LENGTH] ;
332 	struct transaction_log t[] = {
333 		TRXN_START,
334 		TRXN_WRITE3(write_sbk),
335 		TRXN_READ(old_id, _DS1991_ID_LENGTH),
336 		TRXN_WRITE(password, _DS1991_PASSWORD_LENGTH),
337 		TRXN_READ(data, size),
338 		TRXN_END,
339 	};
340 
341 	return BUS_transaction(t, pn) ;
342 }
343 
OW_write_subkey(int subkey,BYTE * password,size_t size,off_t offset,BYTE * data,const struct parsedname * pn)344 static GOOD_OR_BAD OW_write_subkey( int subkey, BYTE * password, size_t size, off_t offset, BYTE * data, const struct parsedname * pn )
345 {
346 	BYTE subkey_addr = subkey_byte[ subkey ] + offset ;
347 	BYTE write_sbk[] = { _1W_WRITE_SUBKEY, subkey_addr, BYTE_INVERSE(subkey_addr), } ;
348 	BYTE old_id[_DS1991_ID_LENGTH] ;
349 	struct transaction_log t[] = {
350 		TRXN_START,
351 		TRXN_WRITE3(write_sbk),
352 		TRXN_READ(old_id, _DS1991_ID_LENGTH),
353 		TRXN_WRITE(password, _DS1991_PASSWORD_LENGTH),
354 		TRXN_WRITE(data, size),
355 		TRXN_END,
356 	};
357 
358 	return BUS_transaction(t, pn) ;
359 }
360 
OW_write_id(int subkey,BYTE * password,BYTE * id,const struct parsedname * pn)361 static GOOD_OR_BAD OW_write_id( int subkey, BYTE * password, BYTE * id, const struct parsedname * pn )
362 {
363 	BYTE scratch_addr = (3<<6) + _DS1991_ID_START ;
364 	BYTE write_scratch[] = { _1W_WRITE_SCRATCHPAD, scratch_addr, BYTE_INVERSE(scratch_addr), } ;
365 	struct transaction_log tcopy[] = {
366 		TRXN_START,
367 		TRXN_WRITE3(write_scratch),
368 		TRXN_WRITE(id, _DS1991_ID_LENGTH),
369 		TRXN_END,
370 	};
371 
372 	BYTE copy_addr = subkey_byte[ subkey ] ;
373 	BYTE copy_scratch[] = { _1W_COPY_SCRATCHPAD, copy_addr, BYTE_INVERSE(copy_addr), } ;
374 	struct transaction_log twrite[] = {
375 		TRXN_START,
376 		TRXN_WRITE3(copy_scratch),
377 		TRXN_WRITE(cp_array[block_IDENT], _DS1991_COPY_BLOCK_LENGTH),
378 		TRXN_WRITE(password, _DS1991_PASSWORD_LENGTH),
379 		TRXN_END,
380 	};
381 
382 	RETURN_BAD_IF_BAD( BUS_transaction(twrite,pn) ) ;
383 	return BUS_transaction(tcopy, pn) ;
384 }
385 
OW_write_password(int subkey,BYTE * old_password,BYTE * new_password,const struct parsedname * pn)386 static GOOD_OR_BAD OW_write_password( int subkey, BYTE * old_password, BYTE * new_password, const struct parsedname * pn )
387 {
388 	BYTE scratch_addr = 0x0C + _DS1991_PASSWORD_START ;
389 	BYTE write_scratch[] = { _1W_WRITE_SCRATCHPAD, scratch_addr, BYTE_INVERSE(scratch_addr), } ;
390 	BYTE copy_addr = subkey_byte[ subkey ] ;
391 	BYTE copy_scratch[] = { _1W_COPY_SCRATCHPAD, copy_addr, BYTE_INVERSE(copy_addr), } ;
392 	struct transaction_log twrite[] = {
393 		TRXN_START,
394 		TRXN_WRITE3(write_scratch),
395 		TRXN_WRITE(new_password, _DS1991_PASSWORD_LENGTH),
396 		TRXN_END,
397 	};
398 	struct transaction_log tcopy[] = {
399 		TRXN_START,
400 		TRXN_WRITE3(copy_scratch),
401 		TRXN_WRITE(cp_array[block_PASSWORD], _DS1991_COPY_BLOCK_LENGTH),
402 		TRXN_WRITE(old_password, _DS1991_PASSWORD_LENGTH),
403 		TRXN_END,
404 	};
405 
406 	RETURN_BAD_IF_BAD( BUS_transaction(twrite,pn) ) ;
407 	return BUS_transaction(tcopy, pn) ;
408 }
409 
ToPassword(char * text,BYTE * psw)410 static GOOD_OR_BAD ToPassword( char * text, BYTE * psw )
411 {
412 	unsigned int  text_length = _DS1991_PASSWORD_LENGTH * 2 ;
413 	char convert_text[ text_length + 1 ] ;
414 
415 	memset( convert_text, '0', text_length ) ;
416 	convert_text[text_length] = '\0' ;
417 	if ( text == NULL ) {
418 		return gbBAD ;
419 	}
420 
421 	if ( strlen( text ) > text_length ) {
422 		LEVEL_DEBUG("Password extension <%s> longer than %d bytes" , text, _DS1991_PASSWORD_LENGTH ) ;
423 		return gbBAD ;
424 	}
425 
426 	strcpy( & convert_text[ text_length - strlen(text) ] , text ) ;
427 	string2bytes( convert_text, psw, _DS1991_PASSWORD_LENGTH ) ;
428 	return gbGOOD ;
429 }
430 
431 
432