Imported Upstream version 1.8.7
[debian/sudo] / plugins / sudoers / prompt.c
1 /*
2  * Copyright (c) 1993-1996,1998-2005, 2007-2013
3  *      Todd C. Miller <Todd.Miller@courtesan.com>
4  *
5  * Permission to use, copy, modify, and distribute this software for any
6  * purpose with or without fee is hereby granted, provided that the above
7  * copyright notice and this permission notice appear in all copies.
8  *
9  * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
10  * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
11  * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
12  * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
13  * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
14  * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
15  * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
16  *
17  * Sponsored in part by the Defense Advanced Research Projects
18  * Agency (DARPA) and Air Force Research Laboratory, Air Force
19  * Materiel Command, USAF, under agreement number F39502-99-1-0512.
20  */
21
22 #include <config.h>
23
24 #include <sys/types.h>
25 #include <stdio.h>
26 #ifdef STDC_HEADERS
27 # include <stdlib.h>
28 # include <stddef.h>
29 #else
30 # ifdef HAVE_STDLIB_H
31 #  include <stdlib.h>
32 # endif
33 #endif /* STDC_HEADERS */
34 #ifdef HAVE_STRING_H
35 # include <string.h>
36 #endif /* HAVE_STRING_H */
37 #ifdef HAVE_STRINGS_H
38 # include <strings.h>
39 #endif /* HAVE_STRINGS_H */
40 #include <pwd.h>
41 #include <grp.h>
42
43 #include "sudoers.h"
44
45 /*
46  * Expand %h and %u escapes in the prompt and pass back the dynamically
47  * allocated result.  Returns the same string if there are no escapes.
48  */
49 char *
50 expand_prompt(const char *old_prompt, const char *user, const char *host)
51 {
52     size_t len, n;
53     int subst;
54     const char *p;
55     char *np, *new_prompt, *endp;
56     debug_decl(expand_prompt, SUDO_DEBUG_AUTH)
57
58     /* How much space do we need to malloc for the prompt? */
59     subst = 0;
60     for (p = old_prompt, len = strlen(old_prompt); *p; p++) {
61         if (p[0] =='%') {
62             switch (p[1]) {
63                 case 'h':
64                     p++;
65                     len += strlen(user_shost) - 2;
66                     subst = 1;
67                     break;
68                 case 'H':
69                     p++;
70                     len += strlen(user_host) - 2;
71                     subst = 1;
72                     break;
73                 case 'p':
74                     p++;
75                     if (def_rootpw)
76                             len += 2;
77                     else if (def_targetpw || def_runaspw)
78                             len += strlen(runas_pw->pw_name) - 2;
79                     else
80                             len += strlen(user_name) - 2;
81                     subst = 1;
82                     break;
83                 case 'u':
84                     p++;
85                     len += strlen(user_name) - 2;
86                     subst = 1;
87                     break;
88                 case 'U':
89                     p++;
90                     len += strlen(runas_pw->pw_name) - 2;
91                     subst = 1;
92                     break;
93                 case '%':
94                     p++;
95                     len--;
96                     subst = 1;
97                     break;
98                 default:
99                     break;
100             }
101         }
102     }
103
104     if (subst) {
105         new_prompt = emalloc(++len);
106         endp = new_prompt + len;
107         for (p = old_prompt, np = new_prompt; *p; p++) {
108             if (p[0] =='%') {
109                 switch (p[1]) {
110                     case 'h':
111                         p++;
112                         n = strlcpy(np, user_shost, np - endp);
113                         if (n >= np - endp)
114                             goto oflow;
115                         np += n;
116                         continue;
117                     case 'H':
118                         p++;
119                         n = strlcpy(np, user_host, np - endp);
120                         if (n >= np - endp)
121                             goto oflow;
122                         np += n;
123                         continue;
124                     case 'p':
125                         p++;
126                         if (def_rootpw)
127                                 n = strlcpy(np, "root", np - endp);
128                         else if (def_targetpw || def_runaspw)
129                                 n = strlcpy(np, runas_pw->pw_name, np - endp);
130                         else
131                                 n = strlcpy(np, user_name, np - endp);
132                         if (n >= np - endp)
133                                 goto oflow;
134                         np += n;
135                         continue;
136                     case 'u':
137                         p++;
138                         n = strlcpy(np, user_name, np - endp);
139                         if (n >= np - endp)
140                             goto oflow;
141                         np += n;
142                         continue;
143                     case 'U':
144                         p++;
145                         n = strlcpy(np,  runas_pw->pw_name, np - endp);
146                         if (n >= np - endp)
147                             goto oflow;
148                         np += n;
149                         continue;
150                     case '%':
151                         /* convert %% -> % */
152                         p++;
153                         break;
154                     default:
155                         /* no conversion */
156                         break;
157                 }
158             }
159             *np++ = *p;
160             if (np >= endp)
161                 goto oflow;
162         }
163         *np = '\0';
164     } else
165         new_prompt = estrdup(old_prompt);
166
167     debug_return_str(new_prompt);
168
169 oflow:
170     /* We pre-allocate enough space, so this should never happen. */
171     fatalx(_("internal error, %s overflow"), "expand_prompt()");
172 }