1 /*
2  * Amanda, The Advanced Maryland Automatic Network Disk Archiver
3  * Copyright (c) 1991-1999 University of Maryland at College Park
4  * Copyright (c) 2007-2013 Zmanda, Inc.  All Rights Reserved.
5  * All Rights Reserved.
6  *
7  * Permission to use, copy, modify, distribute, and sell this software and its
8  * documentation for any purpose is hereby granted without fee, provided that
9  * the above copyright notice appear in all copies and that both that
10  * copyright notice and this permission notice appear in supporting
11  * documentation, and that the name of U.M. not be used in advertising or
12  * publicity pertaining to distribution of the software without specific,
13  * written prior permission.  U.M. makes no representations about the
14  * suitability of this software for any purpose.  It is provided "as is"
15  * without express or implied warranty.
16  *
17  * U.M. DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING ALL
18  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL U.M.
19  * BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
20  * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION
21  * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
22  * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
23  *
24  * Authors: the Amanda Development Team.  Its members are listed in a
25  * file named AUTHORS, in the root directory of this distribution.
26  */
27 /*
28  * $Id: alloc.c 5280 2007-02-13 15:58:56Z martineau $
29  *
30  * Memory allocators with error handling.  If the allocation fails,
31  * errordump() is called, relieving the caller from checking the return
32  * code
33  */
34 #include "amanda.h"
35 #include "arglist.h"
36 
37 #define	MIN_ALLOC	64
38 
39 static char *internal_vstralloc(const char *, int, const char *, va_list);
40 
41 /*
42  * alloc - a wrapper for malloc.
43  */
44 void *
debug_alloc(const char * file,int line,size_t size)45 debug_alloc(
46     const char *file,
47     int		line,
48     size_t	size)
49 {
50     void *addr;
51 
52     addr = (void *)malloc(max(size, 1));
53     if (addr == NULL) {
54 	errordump(_("%s@%d: memory allocation failed (%zu bytes requested)"),
55 		  file ? file : _("(unknown)"),
56 		  file ? line : -1,
57 		  size);
58 	/*NOTREACHED*/
59     }
60     return addr;
61 }
62 
63 
64 /*
65  * newalloc - free existing buffer and then alloc a new one.
66  */
67 void *
debug_newalloc(const char * file,int line,void * old,size_t size)68 debug_newalloc(
69     const char *file,
70     int		line,
71     void *	old,
72     size_t	size)
73 {
74     char *addr;
75 
76     addr = debug_alloc(file, line, size);
77     amfree(old);
78     return addr;
79 }
80 
81 
82 /*
83  * stralloc - copies the given string into newly allocated memory.
84  *            Just like strdup()!
85  */
86 char *
debug_stralloc(const char * file,int line,const char * str)87 debug_stralloc(
88     const char *file,
89     int		line,
90     const char *str)
91 {
92     char *addr;
93 
94     addr = debug_alloc(file, line, strlen(str) + 1);
95     strcpy(addr, str);
96     return (addr);
97 }
98 
99 /*
100  * internal_vstralloc - copies up to MAX_STR_ARGS strings into newly
101  * allocated memory.
102  *
103  * The MAX_STR_ARGS limit is purely an efficiency issue so we do not have
104  * to scan the strings more than necessary.
105  */
106 
107 #define	MAX_VSTRALLOC_ARGS	40
108 
109 static char *
internal_vstralloc(const char * file,int line,const char * str,va_list argp)110 internal_vstralloc(
111     const char *file,
112     int		line,
113     const char *str,
114     va_list argp)
115 {
116     char *next;
117     char *result;
118     int a, b;
119     size_t total_len;
120     const char *arg[MAX_VSTRALLOC_ARGS+1];
121     size_t len[MAX_VSTRALLOC_ARGS+1];
122     size_t l;
123 
124     if (str == NULL) {
125 	errordump(_("internal_vstralloc: str is NULL"));
126 	/*NOTREACHED*/
127     }
128 
129     a = 0;
130     arg[a] = str;
131     l = strlen(str);
132     total_len = len[a] = l;
133     a++;
134 
135     while ((next = arglist_val(argp, char *)) != NULL) {
136 	if ((l = strlen(next)) == 0) {
137 	    continue;				/* minor optimisation */
138 	}
139 	if (a >= MAX_VSTRALLOC_ARGS) {
140 	    errordump(_("%s@%d: more than %d args to vstralloc"),
141 		      file ? file : _("(unknown)"),
142 		      file ? line : -1,
143 		      MAX_VSTRALLOC_ARGS);
144 	    /*NOTREACHED*/
145 	}
146 	arg[a] = next;
147 	len[a] = l;
148 	total_len += l;
149 	a++;
150     }
151 
152     result = debug_alloc(file, line, total_len+1);
153 
154     next = result;
155     for (b = 0; b < a; b++) {
156 	memcpy(next, arg[b], len[b]);
157 	next += len[b];
158     }
159     *next = '\0';
160 
161     return result;
162 }
163 
164 
165 /*
166  * vstralloc - copies multiple strings into newly allocated memory.
167  */
168 char *
debug_vstralloc(const char * file,int line,const char * str,...)169 debug_vstralloc(
170     const char *file,
171     int		line,
172     const char *str,
173     ...)
174 {
175     va_list argp;
176     char *result;
177 
178     arglist_start(argp, str);
179     result = internal_vstralloc(file, line, str, argp);
180     arglist_end(argp);
181     return result;
182 }
183 
184 
185 /*
186  * newstralloc - free existing string and then stralloc a new one.
187  */
188 char *
debug_newstralloc(const char * file,int line,char * oldstr,const char * newstr)189 debug_newstralloc(
190     const char *file,
191     int		line,
192     char *	oldstr,
193     const char *newstr)
194 {
195     char *addr;
196 
197     addr = debug_stralloc(file, line, newstr);
198     amfree(oldstr);
199     return (addr);
200 }
201 
202 
203 /*
204  * newvstralloc - free existing string and then vstralloc a new one.
205  */
206 char *
debug_newvstralloc(const char * file,int line,char * oldstr,const char * newstr,...)207 debug_newvstralloc(
208     const char *file,
209     int		line,
210     char *	oldstr,
211     const char *newstr,
212     ...)
213 {
214     va_list argp;
215     char *result;
216 
217     arglist_start(argp, newstr);
218     result = internal_vstralloc(file, line, newstr, argp);
219     arglist_end(argp);
220     amfree(oldstr);
221     return result;
222 }
223 
224 
225 /*
226  * vstrallocf - copies printf formatted string into newly allocated memory.
227  */
228 char *
debug_vstrallocf(const char * file,int line,const char * fmt,...)229 debug_vstrallocf(
230     const char *file,
231     int		line,
232     const char *fmt,
233     ...)
234 {
235     char *	result;
236     size_t	size;
237     va_list	argp;
238 
239 
240     result = debug_alloc(file, line, MIN_ALLOC);
241     if (result != NULL) {
242 
243 	arglist_start(argp, fmt);
244 	size = g_vsnprintf(result, MIN_ALLOC, fmt, argp);
245 	arglist_end(argp);
246 
247 	if (size >= (size_t)MIN_ALLOC) {
248 	    amfree(result);
249 	    result = debug_alloc(file, line, size + 1);
250 
251 	    arglist_start(argp, fmt);
252 	    (void)g_vsnprintf(result, size + 1, fmt, argp);
253 	    arglist_end(argp);
254 	}
255     }
256 
257     return result;
258 }
259 
260 
261 /*
262  * newvstrallocf - free existing string and then vstrallocf a new one.
263  */
264 char *
debug_newvstrallocf(const char * file,int line,char * oldstr,const char * fmt,...)265 debug_newvstrallocf(
266     const char *file,
267     int		line,
268     char *	oldstr,
269     const char *fmt,
270     ...)
271 {
272     size_t	size;
273     char *	result;
274     va_list	argp;
275 
276     result = debug_alloc(file, line, MIN_ALLOC);
277     if (result != NULL) {
278 
279 	arglist_start(argp, fmt);
280 	size = g_vsnprintf(result, MIN_ALLOC, fmt, argp);
281 	arglist_end(argp);
282 
283 	if (size >= MIN_ALLOC) {
284 	    amfree(result);
285 	    result = debug_alloc(file, line, size + 1);
286 
287 	    arglist_start(argp, fmt);
288 	    (void)g_vsnprintf(result, size + 1, fmt, argp);
289 	    arglist_end(argp);
290 	}
291     }
292     amfree(oldstr);
293     return result;
294 }
295 
296 /* vstrextend -- Extends the existing string by appending the other
297  * arguments. */
298 char *
debug_vstrextend(const char * file,int line,char ** oldstr,...)299 debug_vstrextend(
300     const char *file,
301     int		line,
302     char **	oldstr,
303     ...)
304 {
305 	char *keep = *oldstr;
306 	va_list ap;
307 
308 	arglist_start(ap, oldstr);
309 
310 	if (*oldstr == NULL)
311 		*oldstr = "";
312 	*oldstr = internal_vstralloc(file, line, *oldstr, ap);
313         amfree(keep);
314 
315 	arglist_end(ap);
316         return *oldstr;
317 }
318 
319 /*
320  * safe_env_full - build a "safe" environment list.
321  */
322 char **
safe_env_full(char ** add)323 safe_env_full(char **add)
324 {
325     static char *safe_env_list[] = {
326 	"TZ",
327 #ifdef __CYGWIN__
328 	"SYSTEMROOT",
329 #endif
330 #ifdef NEED_PATH_ENV
331 	"PATH",
332 #endif
333 	"DISPLAY",
334 #ifdef NEED_LD_LIBRARY_PATH_ENV
335 	"LD_LIBRARY_PATH",
336 #endif
337 	NULL
338     };
339 
340     /*
341      * If the initial environment pointer malloc fails, set up to
342      * pass back a pointer to the NULL string pointer at the end of
343      * safe_env_list so our result is always a valid, although possibly
344      * empty, environment list.
345      */
346 #define SAFE_ENV_CNT	(size_t)(sizeof(safe_env_list) / sizeof(*safe_env_list))
347     char **envp = safe_env_list + SAFE_ENV_CNT - 1;
348 
349     char **p;
350     char **q;
351     char *s;
352     char *v;
353     size_t l1, l2;
354     char **env;
355     int    env_cnt;
356     int nadd = 0;
357 
358     /* count ADD */
359     for (p = add; p && *p; p++)
360 	nadd++;
361 
362     if (getuid() == geteuid() && getgid() == getegid()) {
363 	env_cnt = 1;
364 	for (env = environ; *env != NULL; env++)
365 	    env_cnt++;
366 	if ((q = (char **)malloc((nadd+env_cnt)*SIZEOF(char *))) != NULL) {
367 	    envp = q;
368 	    p = envp;
369 	    /* copy in ADD */
370 	    for (env = add; env && *env; env++) {
371 		*p = *env;
372 		p++;
373 	    }
374 	    for (env = environ; *env != NULL; env++) {
375 		if (strncmp("LANG=", *env, 5) != 0 &&
376 		    strncmp("LC_", *env, 3) != 0) {
377 		    *p = stralloc(*env);
378 		    p++;
379 		}
380 	    }
381 	    *p = NULL;
382 	}
383 	return envp;
384     }
385 
386     if ((q = (char **)malloc(nadd*sizeof(char *) + SIZEOF(safe_env_list))) != NULL) {
387 	envp = q;
388 	/* copy in ADD */
389 	for (p = add; p && *p; p++) {
390 	    *q = *p;
391 	    q++;
392 	}
393 
394 	/* and copy any SAFE_ENV that are already set */
395 	for (p = safe_env_list; *p != NULL; p++) {
396 	    if ((v = getenv(*p)) == NULL) {
397 		continue;			/* no variable to dup */
398 	    }
399 	    l1 = strlen(*p);			/* variable name w/o null */
400 	    l2 = strlen(v) + 1;			/* include null byte here */
401 	    if ((s = (char *)malloc(l1 + 1 + l2)) == NULL) {
402 		break;				/* out of memory */
403 	    }
404 	    *q++ = s;				/* save the new pointer */
405 	    memcpy(s, *p, l1);			/* left hand side */
406 	    s += l1;
407 	    *s++ = '=';
408 	    memcpy(s, v, l2);			/* right hand side and null */
409 	}
410 	*q = NULL;				/* terminate the list */
411     }
412     return envp;
413 }
414