lib: Fix CID 1441264 Error handling issues (CHECKED_RETURN)
[garming/samba-autobuild/.git] / source3 / lib / util_path.c
1 /*
2  * Unix SMB/CIFS implementation.
3  * Samba utility functions
4  * Copyright (C) Andrew Tridgell 1992-1998
5  * Copyright (C) Jeremy Allison 2001-2007
6  * Copyright (C) Simo Sorce 2001
7  * Copyright (C) Jim McDonough <jmcd@us.ibm.com> 2003
8  * Copyright (C) James Peach 2006
9  *
10  * This program is free software; you can redistribute it and/or modify
11  * it under the terms of the GNU General Public License as published by
12  * the Free Software Foundation; either version 3 of the License, or
13  * (at your option) any later version.
14  *
15  * This program is distributed in the hope that it will be useful,
16  * but WITHOUT ANY WARRANTY; without even the implied warranty of
17  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
18  * GNU General Public License for more details.
19  *
20  * You should have received a copy of the GNU General Public License
21  * along with this program.  If not, see <http://www.gnu.org/licenses/>.
22  */
23
24 #include "replace.h"
25 #include <talloc.h>
26 #include "lib/util/samba_util.h"
27 #include "lib/util_path.h"
28
29 struct share_params;
30 #include "source3/param/param_proto.h"
31
32 /**
33  * @brief Returns an absolute path to a file concatenating the provided
34  * @a rootpath and @a basename
35  *
36  * @param name Filename, relative to @a rootpath
37  *
38  * @retval Pointer to a string containing the full path.
39  **/
40
41 static char *xx_path(TALLOC_CTX *mem_ctx,
42                      const char *name,
43                      const char *rootpath)
44 {
45         char *fname = NULL;
46
47         fname = talloc_strdup(mem_ctx, rootpath);
48         if (!fname) {
49                 return NULL;
50         }
51         trim_string(fname,"","/");
52
53         if (!directory_create_or_exist(fname, 0755)) {
54                 return NULL;
55         }
56
57         return talloc_asprintf_append(fname, "/%s", name);
58 }
59
60 /**
61  * @brief Returns an absolute path to a file in the Samba lock directory.
62  *
63  * @param name File to find, relative to LOCKDIR.
64  *
65  * @retval Pointer to a talloc'ed string containing the full path.
66  **/
67
68 char *lock_path(TALLOC_CTX *mem_ctx, const char *name)
69 {
70         return xx_path(mem_ctx, name, lp_lock_directory());
71 }
72
73 /**
74  * @brief Returns an absolute path to a file in the Samba state directory.
75  *
76  * @param name File to find, relative to STATEDIR.
77  *
78  * @retval Pointer to a talloc'ed string containing the full path.
79  **/
80
81 char *state_path(TALLOC_CTX *mem_ctx, const char *name)
82 {
83         return xx_path(mem_ctx, name, lp_state_directory());
84 }
85
86 /**
87  * @brief Returns an absolute path to a file in the Samba cache directory.
88  *
89  * @param name File to find, relative to CACHEDIR.
90  *
91  * @retval Pointer to a talloc'ed string containing the full path.
92  **/
93
94 char *cache_path(TALLOC_CTX *mem_ctx, const char *name)
95 {
96         return xx_path(mem_ctx, name, lp_cache_directory());
97 }
98
99 /**
100  * @brief Removes any invalid path components in an absolute POSIX path.
101  *
102  * @param ctx Talloc context to return string.
103  *
104  * @param abs_path Absolute path string to process.
105  *
106  * @retval Pointer to a talloc'ed string containing the absolute full path.
107  **/
108
109 char *canonicalize_absolute_path(TALLOC_CTX *ctx, const char *abs_path)
110 {
111         char *destname;
112         char *d;
113         const char *s = abs_path;
114         bool start_of_name_component = true;
115
116         /* Allocate for strlen + '\0' + possible leading '/' */
117         destname = (char *)talloc_size(ctx, strlen(abs_path) + 2);
118         if (destname == NULL) {
119                 return NULL;
120         }
121         d = destname;
122
123         *d++ = '/'; /* Always start with root. */
124
125         while (*s) {
126                 if (*s == '/') {
127                         /* Eat multiple '/' */
128                         while (*s == '/') {
129                                 s++;
130                         }
131                         if ((d > destname + 1) && (*s != '\0')) {
132                                 *d++ = '/';
133                         }
134                         start_of_name_component = true;
135                         continue;
136                 }
137
138                 if (start_of_name_component) {
139                         if ((s[0] == '.') && (s[1] == '.') &&
140                                         (s[2] == '/' || s[2] == '\0')) {
141                                 /* Uh oh - "/../" or "/..\0" ! */
142
143                                 /* Go past the .. leaving us on the / or '\0' */
144                                 s += 2;
145
146                                 /* If  we just added a '/' - delete it */
147                                 if ((d > destname) && (*(d-1) == '/')) {
148                                         *(d-1) = '\0';
149                                         d--;
150                                 }
151
152                                 /*
153                                  * Are we at the start ?
154                                  * Can't go back further if so.
155                                  */
156                                 if (d <= destname) {
157                                         *d++ = '/'; /* Can't delete root */
158                                         continue;
159                                 }
160                                 /* Go back one level... */
161                                 /*
162                                  * Decrement d first as d points to
163                                  * the *next* char to write into.
164                                  */
165                                 for (d--; d > destname; d--) {
166                                         if (*d == '/') {
167                                                 break;
168                                         }
169                                 }
170
171                                 /*
172                                  * Are we at the start ?
173                                  * Can't go back further if so.
174                                  */
175                                 if (d <= destname) {
176                                         *d++ = '/'; /* Can't delete root */
177                                         continue;
178                                 }
179
180                                 /*
181                                  * We're still at the start of a name
182                                  * component, just the previous one.
183                                  */
184                                 continue;
185                         } else if ((s[0] == '.') &&
186                                         ((s[1] == '\0') || s[1] == '/')) {
187                                 /*
188                                  * Component of pathname can't be "." only.
189                                  * Skip the '.' .
190                                  */
191                                 if (s[1] == '/') {
192                                         s += 2;
193                                 } else {
194                                         s++;
195                                 }
196                                 continue;
197                         }
198                 }
199
200                 if (!(*s & 0x80)) {
201                         *d++ = *s++;
202                 } else {
203                         size_t siz;
204                         /* Get the size of the next MB character. */
205                         next_codepoint(s,&siz);
206                         switch(siz) {
207                                 case 5:
208                                         *d++ = *s++;
209
210                                         FALL_THROUGH;
211                                 case 4:
212                                         *d++ = *s++;
213
214                                         FALL_THROUGH;
215                                 case 3:
216                                         *d++ = *s++;
217
218                                         FALL_THROUGH;
219                                 case 2:
220                                         *d++ = *s++;
221
222                                         FALL_THROUGH;
223                                 case 1:
224                                         *d++ = *s++;
225                                         break;
226                                 default:
227                                         break;
228                         }
229                 }
230                 start_of_name_component = false;
231         }
232         *d = '\0';
233
234         /* And must not end in '/' */
235         if (d > destname + 1 && (*(d-1) == '/')) {
236                 *(d-1) = '\0';
237         }
238
239         return destname;
240 }