1/**
2 * object_id.c - Processing of object ids
3 *
4 *	This module is part of ntfs-3g library
5 *
6 * Copyright (c) 2009-2019 Jean-Pierre Andre
7 *
8 * This program/include file is free software; you can redistribute it and/or
9 * modify it under the terms of the GNU General Public License as published
10 * by the Free Software Foundation; either version 2 of the License, or
11 * (at your option) any later version.
12 *
13 * This program/include file is distributed in the hope that it will be
14 * useful, but WITHOUT ANY WARRANTY; without even the implied warranty
15 * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
16 * GNU General Public License for more details.
17 *
18 * You should have received a copy of the GNU General Public License
19 * along with this program (in the main directory of the NTFS-3G
20 * distribution in the file COPYING); if not, write to the Free Software
21 * Foundation,Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
22 */
23
24#ifdef HAVE_CONFIG_H
25#include "config.h"
26#endif
27
28#ifdef HAVE_STDLIB_H
29#include <stdlib.h>
30#endif
31#ifdef HAVE_ERRNO_H
32#include <errno.h>
33#endif
34#ifdef HAVE_STRING_H
35#include <string.h>
36#endif
37#ifdef HAVE_SYS_STAT_H
38#include <sys/stat.h>
39#endif
40#ifdef HAVE_SYS_SYSMACROS_H
41#include <sys/sysmacros.h>
42#endif
43
44#include "compat.h"
45#include "types.h"
46#include "debug.h"
47#include "attrib.h"
48#include "inode.h"
49#include "dir.h"
50#include "volume.h"
51#include "mft.h"
52#include "index.h"
53#include "lcnalloc.h"
54#include "object_id.h"
55#include "logging.h"
56#include "misc.h"
57#include "xattrs.h"
58
59/*
60 *			Endianness considerations
61 *
62 *	According to RFC 4122, GUIDs should be printed with the most
63 *	significant byte first, and the six fields be compared individually
64 *	for ordering. RFC 4122 does not define the internal representation.
65 *
66 *	Windows apparently stores the first three fields in little endian
67 *	order, and the last two fields in big endian order.
68 *
69 *	Here we always copy disk images with no endianness change,
70 *	and, for indexing, GUIDs are compared as if they were a sequence
71 *	of four little-endian unsigned 32 bit integers (as Windows
72 *	does it that way.)
73 *
74 * --------------------- begin from RFC 4122 ----------------------
75 * Consider each field of the UUID to be an unsigned integer as shown
76 * in the table in section Section 4.1.2.  Then, to compare a pair of
77 * UUIDs, arithmetically compare the corresponding fields from each
78 * UUID in order of significance and according to their data type.
79 * Two UUIDs are equal if and only if all the corresponding fields
80 * are equal.
81 *
82 * UUIDs, as defined in this document, can also be ordered
83 * lexicographically.  For a pair of UUIDs, the first one follows the
84 * second if the most significant field in which the UUIDs differ is
85 * greater for the first UUID.  The second precedes the first if the
86 * most significant field in which the UUIDs differ is greater for
87 * the second UUID.
88 *
89 * The fields are encoded as 16 octets, with the sizes and order of the
90 * fields defined above, and with each field encoded with the Most
91 * Significant Byte first (known as network byte order).  Note that the
92 * field names, particularly for multiplexed fields, follow historical
93 * practice.
94 *
95 * 0                   1                   2                   3
96 *  0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
97 * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
98 * |                          time_low                             |
99 * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
100 * |       time_mid                |         time_hi_and_version   |
101 * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
102 * |clk_seq_hi_res |  clk_seq_low  |         node (0-1)            |
103 * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
104 * |                         node (2-5)                            |
105 * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
106 *
107 * ---------------------- end from RFC 4122 -----------------------
108 */
109
110typedef struct {
111	union {
112		/* alignment may be needed to evaluate collations */
113		u32 alignment;
114		GUID guid;
115	} object_id;
116} OBJECT_ID_INDEX_KEY;
117
118typedef struct {
119	le64 file_id;
120	GUID birth_volume_id;
121	GUID birth_object_id;
122	GUID domain_id;
123} OBJECT_ID_INDEX_DATA; // known as OBJ_ID_INDEX_DATA
124
125struct OBJECT_ID_INDEX {		/* index entry in $Extend/$ObjId */
126	INDEX_ENTRY_HEADER header;
127	OBJECT_ID_INDEX_KEY key;
128	OBJECT_ID_INDEX_DATA data;
129} ;
130
131static ntfschar objid_index_name[] = { const_cpu_to_le16('$'),
132					 const_cpu_to_le16('O') };
133
134/*
135 *			Set the index for a new object id
136 *
137 *	Returns 0 if success
138 *		-1 if failure, explained by errno
139 */
140
141static int set_object_id_index(ntfs_inode *ni, ntfs_index_context *xo,
142			const OBJECT_ID_ATTR *object_id)
143{
144	struct OBJECT_ID_INDEX indx;
145	u64 file_id_cpu;
146	le64 file_id;
147	le16 seqn;
148
149	seqn = ni->mrec->sequence_number;
150	file_id_cpu = MK_MREF(ni->mft_no,le16_to_cpu(seqn));
151	file_id = cpu_to_le64(file_id_cpu);
152	indx.header.data_offset = const_cpu_to_le16(
153					sizeof(INDEX_ENTRY_HEADER)
154					+ sizeof(OBJECT_ID_INDEX_KEY));
155	indx.header.data_length = const_cpu_to_le16(
156					sizeof(OBJECT_ID_INDEX_DATA));
157	indx.header.reservedV = const_cpu_to_le32(0);
158	indx.header.length = const_cpu_to_le16(
159					sizeof(struct OBJECT_ID_INDEX));
160	indx.header.key_length = const_cpu_to_le16(
161					sizeof(OBJECT_ID_INDEX_KEY));
162	indx.header.flags = const_cpu_to_le16(0);
163	indx.header.reserved = const_cpu_to_le16(0);
164
165	memcpy(&indx.key.object_id,object_id,sizeof(GUID));
166
167	indx.data.file_id = file_id;
168	memcpy(&indx.data.birth_volume_id,
169			&object_id->birth_volume_id,sizeof(GUID));
170	memcpy(&indx.data.birth_object_id,
171			&object_id->birth_object_id,sizeof(GUID));
172	memcpy(&indx.data.domain_id,
173			&object_id->domain_id,sizeof(GUID));
174	ntfs_index_ctx_reinit(xo);
175	return (ntfs_ie_add(xo,(INDEX_ENTRY*)&indx));
176}
177
178/*
179 *		Open the $Extend/$ObjId file and its index
180 *
181 *	Return the index context if opened
182 *		or NULL if an error occurred (errno tells why)
183 *
184 *	The index has to be freed and inode closed when not needed any more.
185 */
186
187static ntfs_index_context *open_object_id_index(ntfs_volume *vol)
188{
189	u64 inum;
190	ntfs_inode *ni;
191	ntfs_inode *dir_ni;
192	ntfs_index_context *xo;
193
194		/* do not use path_name_to inode - could reopen root */
195	dir_ni = ntfs_inode_open(vol, FILE_Extend);
196	ni = (ntfs_inode*)NULL;
197	if (dir_ni) {
198		inum = ntfs_inode_lookup_by_mbsname(dir_ni,"$ObjId");
199		if (inum != (u64)-1)
200			ni = ntfs_inode_open(vol, inum);
201		ntfs_inode_close(dir_ni);
202	}
203	if (ni) {
204		xo = ntfs_index_ctx_get(ni, objid_index_name, 2);
205		if (!xo) {
206			ntfs_inode_close(ni);
207		}
208	} else
209		xo = (ntfs_index_context*)NULL;
210	return (xo);
211}
212
213
214/*
215 *		Merge object_id data stored in the index into
216 *	a full object_id struct.
217 *
218 *	returns 0 if merging successful
219 *		-1 if no data could be merged. This is generally not an error
220 */
221
222static int merge_index_data(ntfs_inode *ni,
223			const OBJECT_ID_ATTR *objectid_attr,
224			OBJECT_ID_ATTR *full_objectid)
225{
226	OBJECT_ID_INDEX_KEY key;
227	struct OBJECT_ID_INDEX *entry;
228	ntfs_index_context *xo;
229	ntfs_inode *xoni;
230	int res;
231
232	res = -1;
233	xo = open_object_id_index(ni->vol);
234	if (xo) {
235		memcpy(&key.object_id,objectid_attr,sizeof(GUID));
236		if (!ntfs_index_lookup(&key,
237				sizeof(OBJECT_ID_INDEX_KEY), xo)) {
238			entry = (struct OBJECT_ID_INDEX*)xo->entry;
239			/* make sure inode numbers match */
240			if (entry
241			    && (MREF(le64_to_cpu(entry->data.file_id))
242					== ni->mft_no)) {
243				memcpy(&full_objectid->birth_volume_id,
244						&entry->data.birth_volume_id,
245						sizeof(GUID));
246				memcpy(&full_objectid->birth_object_id,
247						&entry->data.birth_object_id,
248						sizeof(GUID));
249				memcpy(&full_objectid->domain_id,
250						&entry->data.domain_id,
251						sizeof(GUID));
252				res = 0;
253			}
254		}
255		xoni = xo->ni;
256		ntfs_index_ctx_put(xo);
257		ntfs_inode_close(xoni);
258	}
259	return (res);
260}
261
262
263/*
264 *		Remove an object id index entry if attribute present
265 *
266 *	Returns the size of existing object id
267 *			(the existing object_d is returned)
268 *		-1 if failure, explained by errno
269 */
270
271static int remove_object_id_index(ntfs_attr *na, ntfs_index_context *xo,
272				OBJECT_ID_ATTR *old_attr)
273{
274	OBJECT_ID_INDEX_KEY key;
275	struct OBJECT_ID_INDEX *entry;
276	s64 size;
277	int ret;
278
279	ret = na->data_size;
280	if (ret) {
281			/* read the existing object id attribute */
282		size = ntfs_attr_pread(na, 0, sizeof(GUID), old_attr);
283		if (size >= (s64)sizeof(GUID)) {
284			memcpy(&key.object_id,
285				&old_attr->object_id,sizeof(GUID));
286			if (!ntfs_index_lookup(&key,
287					sizeof(OBJECT_ID_INDEX_KEY), xo)) {
288				entry = (struct OBJECT_ID_INDEX*)xo->entry;
289				memcpy(&old_attr->birth_volume_id,
290					&entry->data.birth_volume_id,
291					sizeof(GUID));
292				memcpy(&old_attr->birth_object_id,
293					&entry->data.birth_object_id,
294					sizeof(GUID));
295				memcpy(&old_attr->domain_id,
296					&entry->data.domain_id,
297					sizeof(GUID));
298				if (ntfs_index_rm(xo))
299					ret = -1;
300			}
301		} else {
302			ret = -1;
303			errno = ENODATA;
304		}
305	}
306	return (ret);
307}
308
309
310/*
311 *		Update the object id and index
312 *
313 *	The object_id attribute should have been created and the
314 *	non-duplication of the GUID should have been checked before.
315 *
316 *	Returns 0 if success
317 *		-1 if failure, explained by errno
318 *	If could not remove the existing index, nothing is done,
319 *	If could not write the new data, no index entry is inserted
320 *	If failed to insert the index, data is removed
321 */
322
323static int update_object_id(ntfs_inode *ni, ntfs_index_context *xo,
324			const OBJECT_ID_ATTR *value, size_t size)
325{
326	OBJECT_ID_ATTR old_attr;
327	ntfs_attr *na;
328	int oldsize;
329	int written;
330	int res;
331
332	res = 0;
333
334	na = ntfs_attr_open(ni, AT_OBJECT_ID, AT_UNNAMED, 0);
335	if (na) {
336		memset(&old_attr, 0, sizeof(OBJECT_ID_ATTR));
337			/* remove the existing index entry */
338		oldsize = remove_object_id_index(na,xo,&old_attr);
339		if (oldsize < 0)
340			res = -1;
341		else {
342			/* resize attribute */
343			res = ntfs_attr_truncate(na, (s64)sizeof(GUID));
344				/* write the object_id in attribute */
345			if (!res && value) {
346				written = (int)ntfs_attr_pwrite(na,
347					(s64)0, (s64)sizeof(GUID),
348					&value->object_id);
349				if (written != (s64)sizeof(GUID)) {
350					ntfs_log_error("Failed to update "
351							"object id\n");
352					errno = EIO;
353					res = -1;
354				}
355			}
356				/* overwrite index data with new value */
357			memcpy(&old_attr, value,
358				(size < sizeof(OBJECT_ID_ATTR)
359					? size : sizeof(OBJECT_ID_ATTR)));
360			if (!res
361			    && set_object_id_index(ni,xo,&old_attr)) {
362				/*
363				 * If cannot index, try to remove the object
364				 * id and log the error. There will be an
365				 * inconsistency if removal fails.
366				 */
367				ntfs_attr_rm(na);
368				ntfs_log_error("Failed to index object id."
369						" Possible corruption.\n");
370			}
371		}
372		ntfs_attr_close(na);
373		NInoSetDirty(ni);
374	} else
375		res = -1;
376	return (res);
377}
378
379/*
380 *		Add a (dummy) object id to an inode if it does not exist
381 *
382 *	returns 0 if attribute was inserted (or already present)
383 *		-1 if adding failed (explained by errno)
384 */
385
386static int add_object_id(ntfs_inode *ni, int flags)
387{
388	int res;
389	u8 dummy;
390
391	res = -1; /* default return */
392	if (!ntfs_attr_exist(ni,AT_OBJECT_ID, AT_UNNAMED,0)) {
393		if (!(flags & XATTR_REPLACE)) {
394			/*
395			 * no object id attribute : add one,
396			 * apparently, this does not feed the new value in
397			 * Note : NTFS version must be >= 3
398			 */
399			if (ni->vol->major_ver >= 3) {
400				res = ntfs_attr_add(ni, AT_OBJECT_ID,
401						AT_UNNAMED, 0, &dummy, (s64)0);
402				NInoSetDirty(ni);
403			} else
404				errno = EOPNOTSUPP;
405		} else
406			errno = ENODATA;
407	} else {
408		if (flags & XATTR_CREATE)
409			errno = EEXIST;
410		else
411			res = 0;
412	}
413	return (res);
414}
415
416
417/*
418 *		Delete an object_id index entry
419 *
420 *	Returns 0 if success
421 *		-1 if failure, explained by errno
422 */
423
424int ntfs_delete_object_id_index(ntfs_inode *ni)
425{
426	ntfs_index_context *xo;
427	ntfs_inode *xoni;
428	ntfs_attr *na;
429	OBJECT_ID_ATTR old_attr;
430	int res;
431
432	res = 0;
433	na = ntfs_attr_open(ni, AT_OBJECT_ID, AT_UNNAMED, 0);
434	if (na) {
435			/*
436			 * read the existing object id
437			 * and un-index it
438			 */
439		xo = open_object_id_index(ni->vol);
440		if (xo) {
441			if (remove_object_id_index(na,xo,&old_attr) < 0)
442				res = -1;
443			xoni = xo->ni;
444			ntfs_index_entry_mark_dirty(xo);
445			NInoSetDirty(xoni);
446			ntfs_index_ctx_put(xo);
447			ntfs_inode_close(xoni);
448		}
449		ntfs_attr_close(na);
450	}
451	return (res);
452}
453
454
455/*
456 *		Get the ntfs object id into an extended attribute
457 *
458 *	If present, the object_id from the attribute and the GUIDs
459 *	from the index are returned (formatted as OBJECT_ID_ATTR)
460 *
461 *	Returns the global size (can be 0, 16 or 64)
462 *		and the buffer is updated if it is long enough
463 */
464
465int ntfs_get_ntfs_object_id(ntfs_inode *ni, char *value, size_t size)
466{
467	OBJECT_ID_ATTR full_objectid;
468	OBJECT_ID_ATTR *objectid_attr;
469	s64 attr_size;
470	int full_size;
471
472	full_size = 0;	/* default to no data and some error to be defined */
473	if (ni) {
474		objectid_attr = (OBJECT_ID_ATTR*)ntfs_attr_readall(ni,
475			AT_OBJECT_ID,(ntfschar*)NULL, 0, &attr_size);
476		if (objectid_attr) {
477				/* restrict to only GUID present in attr */
478			if (attr_size == sizeof(GUID)) {
479				memcpy(&full_objectid.object_id,
480						objectid_attr,sizeof(GUID));
481				full_size = sizeof(GUID);
482					/* get data from index, if any */
483				if (!merge_index_data(ni, objectid_attr,
484						&full_objectid)) {
485					full_size = sizeof(OBJECT_ID_ATTR);
486				}
487				if (full_size <= (s64)size) {
488					if (value)
489						memcpy(value,&full_objectid,
490							full_size);
491					else
492						errno = EINVAL;
493				}
494			} else {
495			/* unexpected size, better return unsupported */
496				errno = EOPNOTSUPP;
497				full_size = 0;
498			}
499			free(objectid_attr);
500		} else
501			errno = ENODATA;
502	}
503	return (full_size ? (int)full_size : -errno);
504}
505
506/*
507 *		Set the object id from an extended attribute
508 *
509 *	The first 16 bytes are the new object id, they can be followed
510 *	by the birth volume id, the birth object id and the domain id.
511 *	If they are not present, their previous value is kept.
512 *	Only the object id is stored into the attribute, all the fields
513 *	are stored into the index.
514 *
515 *	Returns 0, or -1 if there is a problem
516 */
517
518int ntfs_set_ntfs_object_id(ntfs_inode *ni,
519			const char *value, size_t size, int flags)
520{
521	OBJECT_ID_INDEX_KEY key;
522	ntfs_inode *xoni;
523	ntfs_index_context *xo;
524	int res;
525
526	res = 0;
527	if (ni && value && (size >= sizeof(GUID))) {
528		xo = open_object_id_index(ni->vol);
529		if (xo) {
530			/* make sure the GUID was not used elsewhere */
531			memcpy(&key.object_id, value, sizeof(GUID));
532			if ((ntfs_index_lookup(&key,
533					sizeof(OBJECT_ID_INDEX_KEY), xo))
534			    || (MREF_LE(((struct OBJECT_ID_INDEX*)xo->entry)
535					->data.file_id) == ni->mft_no)) {
536				ntfs_index_ctx_reinit(xo);
537				res = add_object_id(ni, flags);
538				if (!res) {
539						/* update value and index */
540					res = update_object_id(ni,xo,
541						(const OBJECT_ID_ATTR*)value,
542						size);
543				}
544			} else {
545					/* GUID is present elsewhere */
546				res = -1;
547				errno = EEXIST;
548			}
549			xoni = xo->ni;
550			ntfs_index_entry_mark_dirty(xo);
551			NInoSetDirty(xoni);
552			ntfs_index_ctx_put(xo);
553			ntfs_inode_close(xoni);
554		} else {
555			res = -1;
556		}
557	} else {
558		errno = EINVAL;
559		res = -1;
560	}
561	return (res ? -1 : 0);
562}
563
564/*
565 *		Remove the object id
566 *
567 *	Returns 0, or -1 if there is a problem
568 */
569
570int ntfs_remove_ntfs_object_id(ntfs_inode *ni)
571{
572	int res;
573	int olderrno;
574	ntfs_attr *na;
575	ntfs_inode *xoni;
576	ntfs_index_context *xo;
577	int oldsize;
578	OBJECT_ID_ATTR old_attr;
579
580	res = 0;
581	if (ni) {
582		/*
583		 * open and delete the object id
584		 */
585		na = ntfs_attr_open(ni, AT_OBJECT_ID,
586			AT_UNNAMED,0);
587		if (na) {
588			/* first remove index (old object id needed) */
589			xo = open_object_id_index(ni->vol);
590			if (xo) {
591				oldsize = remove_object_id_index(na,xo,
592						&old_attr);
593				if (oldsize < 0) {
594					res = -1;
595				} else {
596					/* now remove attribute */
597					res = ntfs_attr_rm(na);
598					if (res
599					    && (oldsize > (int)sizeof(GUID))) {
600					/*
601					 * If we could not remove the
602					 * attribute, try to restore the
603					 * index and log the error. There
604					 * will be an inconsistency if
605					 * the reindexing fails.
606					 */
607						set_object_id_index(ni, xo,
608							&old_attr);
609						ntfs_log_error(
610						"Failed to remove object id."
611						" Possible corruption.\n");
612					}
613				}
614
615				xoni = xo->ni;
616				ntfs_index_entry_mark_dirty(xo);
617				NInoSetDirty(xoni);
618				ntfs_index_ctx_put(xo);
619				ntfs_inode_close(xoni);
620			}
621			olderrno = errno;
622			ntfs_attr_close(na);
623					/* avoid errno pollution */
624			if (errno == ENOENT)
625				errno = olderrno;
626		} else {
627			errno = ENODATA;
628			res = -1;
629		}
630		NInoSetDirty(ni);
631	} else {
632		errno = EINVAL;
633		res = -1;
634	}
635	return (res ? -1 : 0);
636}
637