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