Initial commit for Tizen
[profile/extras/shadow-utils.git] / libmisc / setupenv.c
1 /*
2  * Copyright (c) 1989 - 1994, Julianne Frances Haugh
3  * Copyright (c) 1996 - 2000, Marek Michałkiewicz
4  * Copyright (c) 2001 - 2006, Tomasz Kłoczko
5  * Copyright (c) 2007 - 2009, Nicolas François
6  * All rights reserved.
7  *
8  * Redistribution and use in source and binary forms, with or without
9  * modification, are permitted provided that the following conditions
10  * are met:
11  * 1. Redistributions of source code must retain the above copyright
12  *    notice, this list of conditions and the following disclaimer.
13  * 2. Redistributions in binary form must reproduce the above copyright
14  *    notice, this list of conditions and the following disclaimer in the
15  *    documentation and/or other materials provided with the distribution.
16  * 3. The name of the copyright holders or contributors may not be used to
17  *    endorse or promote products derived from this software without
18  *    specific prior written permission.
19  *
20  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
21  * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
22  * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
23  * PARTICULAR PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE COPYRIGHT
24  * HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
25  * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
26  * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
27  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
28  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
29  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
30  * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
31  */
32
33 /*
34  * Separated from setup.c.  --marekm
35  */
36
37 #include <config.h>
38
39 #ident "$Id: setupenv.c 3034 2009-07-22 13:30:06Z nekral-guest $"
40
41 #include <assert.h>
42 #include <sys/types.h>
43 #include <sys/stat.h>
44 #include <stdio.h>
45 #include <ctype.h>
46 #include "prototypes.h"
47 #include "defines.h"
48 #include <pwd.h>
49 #include "getdef.h"
50
51 #ifndef USE_PAM
52 static void
53 addenv_path (const char *varname, const char *dirname, const char *filename)
54 {
55         char *buf;
56         size_t len = strlen (dirname) + strlen (filename) + 2;
57         int wlen;
58
59         buf = xmalloc (len);
60         wlen = snprintf (buf, len, "%s/%s", dirname, filename);
61         assert (wlen == (int) len - 1);
62
63         addenv (varname, buf);
64         free (buf);
65 }
66
67 static void read_env_file (const char *filename)
68 {
69         FILE *fp;
70         char buf[1024];
71         char *cp, *name, *val;
72
73         fp = fopen (filename, "r");
74         if (NULL == fp) {
75                 return;
76         }
77         while (fgets (buf, sizeof buf, fp) == buf) {
78                 cp = strrchr (buf, '\n');
79                 if (NULL == cp) {
80                         break;
81                 }
82                 *cp = '\0';
83
84                 cp = buf;
85                 /* ignore whitespace and comments */
86                 while (('\0' != *cp) && isspace (*cp)) {
87                         cp++;
88                 }
89                 if (('\0' == *cp) || ('#' == *cp)) {
90                         continue;
91                 }
92                 /*
93                  * ignore lines which don't follow the name=value format
94                  * (for example, the "export NAME" shell commands)
95                  */
96                 name = cp;
97                 while (('\0' != *cp) && !isspace (*cp) && ('=' != *cp)) {
98                         cp++;
99                 }
100                 if ('=' != *cp) {
101                         continue;
102                 }
103                 /* NUL-terminate the name */
104                 *cp = '\0';
105                 cp++;
106                 val = cp;
107 #if 0                           /* XXX untested, and needs rewrite with fewer goto's :-) */
108 /*
109  (state, char_type) -> (state, action)
110
111  state: unquoted, single_quoted, double_quoted, escaped, double_quoted_escaped
112  char_type: normal, white, backslash, single, double
113  action: remove_curr, remove_curr_skip_next, remove_prev, finish XXX
114 */
115               no_quote:
116                 if (*cp == '\\') {
117                         /* remove the backslash */
118                         remove_char (cp);
119                         /* skip over the next character */
120                         if (*cp)
121                                 cp++;
122                         goto no_quote;
123                 } else if (*cp == '\'') {
124                         /* remove the quote */
125                         remove_char (cp);
126                         /* now within single quotes */
127                         goto s_quote;
128                 } else if (*cp == '"') {
129                         /* remove the quote */
130                         remove_char (cp);
131                         /* now within double quotes */
132                         goto d_quote;
133                 } else if (*cp == '\0') {
134                         /* end of string */
135                         goto finished;
136                 } else if (isspace (*cp)) {
137                         /* unescaped whitespace - end of string */
138                         *cp = '\0';
139                         goto finished;
140                 } else {
141                         cp++;
142                         goto no_quote;
143                 }
144               s_quote:
145                 if (*cp == '\'') {
146                         /* remove the quote */
147                         remove_char (cp);
148                         /* unquoted again */
149                         goto no_quote;
150                 } else if (*cp == '\0') {
151                         /* end of string */
152                         goto finished;
153                 } else {
154                         /* preserve everything within single quotes */
155                         cp++;
156                         goto s_quote;
157                 }
158               d_quote:
159                 if (*cp == '\"') {
160                         /* remove the quote */
161                         remove_char (cp);
162                         /* unquoted again */
163                         goto no_quote;
164                 } else if (*cp == '\\') {
165                         cp++;
166                         /* if backslash followed by double quote, remove backslash
167                            else skip over the backslash and following char */
168                         if (*cp == '"')
169                                 remove_char (cp - 1);
170                         else if (*cp)
171                                 cp++;
172                         goto d_quote;
173                 }
174                 eise if (*cp == '\0') {
175                         /* end of string */
176                         goto finished;
177                 } else {
178                         /* preserve everything within double quotes */
179                         goto d_quote;
180                 }
181               finished:
182 #endif                          /* 0 */
183                 /*
184                  * XXX - should handle quotes, backslash escapes, etc.
185                  * like the shell does.
186                  */
187                 addenv (name, val);
188         }
189         (void) fclose (fp);
190 }
191 #endif                          /* USE_PAM */
192
193
194 /*
195  *      change to the user's home directory
196  *      set the HOME, SHELL, MAIL, PATH, and LOGNAME or USER environmental
197  *      variables.
198  */
199
200 void setup_env (struct passwd *info)
201 {
202 #ifndef USE_PAM
203         char *envf;
204 #endif
205         char *cp;
206
207         /*
208          * Change the current working directory to be the home directory
209          * of the user.  It is a fatal error for this process to be unable
210          * to change to that directory.  There is no "default" home
211          * directory.
212          *
213          * We no longer do it as root - should work better on NFS-mounted
214          * home directories.  Some systems default to HOME=/, so we make
215          * this a configurable option.  --marekm
216          */
217
218         if (chdir (info->pw_dir) == -1) {
219                 static char temp_pw_dir[] = "/";
220
221                 if (!getdef_bool ("DEFAULT_HOME") || chdir ("/") == -1) {
222                         fprintf (stderr, _("Unable to cd to '%s'\n"),
223                                  info->pw_dir);
224                         SYSLOG ((LOG_WARN,
225                                  "unable to cd to `%s' for user `%s'\n",
226                                  info->pw_dir, info->pw_name));
227                         closelog ();
228                         exit (EXIT_FAILURE);
229                 }
230                 (void) puts (_("No directory, logging in with HOME=/"));
231                 info->pw_dir = temp_pw_dir;
232         }
233
234         /*
235          * Create the HOME environmental variable and export it.
236          */
237
238         addenv ("HOME", info->pw_dir);
239
240         /*
241          * Create the SHELL environmental variable and export it.
242          */
243
244         if ((NULL == info->pw_shell) || ('\0' == *info->pw_shell)) {
245                 static char temp_pw_shell[] = SHELL;
246
247                 info->pw_shell = temp_pw_shell;
248         }
249
250         addenv ("SHELL", info->pw_shell);
251
252         /*
253          * Export the user name.  For BSD derived systems, it's "USER", for
254          * all others it's "LOGNAME".  We set both of them.
255          */
256
257         addenv ("USER", info->pw_name);
258         addenv ("LOGNAME", info->pw_name);
259
260         /*
261          * Create the PATH environmental variable and export it.
262          */
263
264         cp = getdef_str ((info->pw_uid == 0) ? "ENV_SUPATH" : "ENV_PATH");
265
266         if (NULL == cp) {
267                 /* not specified, use a minimal default */
268                 addenv ("PATH=/bin:/usr/bin", NULL);
269         } else if (strchr (cp, '=')) {
270                 /* specified as name=value (PATH=...) */
271                 addenv (cp, NULL);
272         } else {
273                 /* only value specified without "PATH=" */
274                 addenv ("PATH", cp);
275         }
276
277 #ifndef USE_PAM
278         /*
279          * Create the MAIL environmental variable and export it.  login.defs
280          * knows the prefix.
281          */
282
283         if (getdef_bool ("MAIL_CHECK_ENAB")) {
284                 cp = getdef_str ("MAIL_DIR");
285                 if (NULL != cp) {
286                         addenv_path ("MAIL", cp, info->pw_name);
287                 } else {
288                         cp = getdef_str ("MAIL_FILE");
289                         if (NULL != cp) {
290                                 addenv_path ("MAIL", info->pw_dir, cp);
291                         } else {
292 #if defined(MAIL_SPOOL_FILE)
293                                 addenv_path ("MAIL", info->pw_dir, MAIL_SPOOL_FILE);
294 #elif defined(MAIL_SPOOL_DIR)
295                                 addenv_path ("MAIL", MAIL_SPOOL_DIR, info->pw_name);
296 #endif
297                         }
298                 }
299         }
300
301         /*
302          * Read environment from optional config file.  --marekm
303          */
304         envf = getdef_str ("ENVIRON_FILE");
305         if (NULL != envf) {
306                 read_env_file (envf);
307         }
308 #endif                          /* !USE_PAM */
309 }
310