]> granicus.if.org Git - shadow/blob - src/suauth.c
* src/chage.c, src/chfn.c, src/chgpasswd.c, src/chpasswd.c,
[shadow] / src / suauth.c
1 /*
2  * Copyright (c) 1990 - 1994, Julianne Frances Haugh
3  * Copyright (c) 1996 - 2000, Marek Michałkiewicz
4  * Copyright (c) 2002 - 2005, Tomasz Kłoczko
5  * Copyright (c) 2007 - 2008, 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 #include <config.h>
34 #include <errno.h>
35 #include <grp.h>
36 #include <pwd.h>
37 #include <stdio.h>
38 #include <sys/types.h>
39 #include "defines.h"
40 #include "prototypes.h"
41
42 #ifndef SUAUTHFILE
43 #define SUAUTHFILE "/etc/suauth"
44 #endif
45
46 #define NOACTION        0
47 #define NOPWORD         1
48 #define DENY            -1
49 #define OWNPWORD        2
50
51 #ifdef SU_ACCESS
52
53 /* Really, I could do with a few const char's here defining all the 
54  * strings output to the user or the syslog. -- chris
55  */
56 static int applies (const char *, char *);
57
58 static int isgrp (const char *, const char *);
59
60 static int lines = 0;
61
62
63 int check_su_auth (const char *actual_id,
64                    const char *wanted_id,
65                    bool su_to_root)
66 {
67         int posn, endline;
68         const char field[] = ":";
69         FILE *authfile_fd;
70         char temp[1024];
71         char *to_users;
72         char *from_users;
73         char *action;
74
75         if (!(authfile_fd = fopen (SUAUTHFILE, "r"))) {
76                 int err = errno;
77                 /*
78                  * If the file doesn't exist - default to the standard su
79                  * behaviour (no access control).  If open fails for some
80                  * other reason - maybe someone is trying to fool us with
81                  * file descriptors limit etc., so deny access.  --marekm
82                  */
83                 if (ENOENT == err) {
84                         return NOACTION;
85                 }
86                 SYSLOG ((LOG_ERR,
87                          "could not open/read config file '%s': %s\n",
88                          SUAUTHFILE, strerror (err)));
89                 return DENY;
90         }
91
92         while (fgets (temp, sizeof (temp), authfile_fd) != NULL) {
93                 lines++;
94
95                 if (temp[endline = strlen (temp) - 1] != '\n') {
96                         SYSLOG ((LOG_ERR,
97                                  "%s, line %d: line too long or missing newline",
98                                  SUAUTHFILE, lines));
99                         continue;
100                 }
101
102                 while (endline > 0 && (temp[endline - 1] == ' '
103                                        || temp[endline - 1] == '\t'
104                                        || temp[endline - 1] == '\n'))
105                         endline--;
106                 temp[endline] = '\0';
107
108                 posn = 0;
109                 while (temp[posn] == ' ' || temp[posn] == '\t')
110                         posn++;
111
112                 if (temp[posn] == '\n' || temp[posn] == '#'
113                     || temp[posn] == '\0') {
114                         continue;
115                 }
116                 if (!(to_users = strtok (temp + posn, field))
117                     || !(from_users = strtok ((char *) NULL, field))
118                     || !(action = strtok ((char *) NULL, field))
119                     || strtok ((char *) NULL, field)) {
120                         SYSLOG ((LOG_ERR,
121                                  "%s, line %d. Bad number of fields.\n",
122                                  SUAUTHFILE, lines));
123                         continue;
124                 }
125
126                 if (!applies (wanted_id, to_users))
127                         continue;
128                 if (!applies (actual_id, from_users))
129                         continue;
130                 if (!strcmp (action, "DENY")) {
131                         SYSLOG ((su_to_root ? LOG_WARN : LOG_NOTICE,
132                                  "DENIED su from '%s' to '%s' (%s)\n",
133                                  actual_id, wanted_id, SUAUTHFILE));
134                         fputs (_("Access to su to that account DENIED.\n"),
135                                stderr);
136                         fclose (authfile_fd);
137                         return DENY;
138                 } else if (!strcmp (action, "NOPASS")) {
139                         SYSLOG ((su_to_root ? LOG_NOTICE : LOG_INFO,
140                                  "NO password asked for su from '%s' to '%s' (%s)\n",
141                                  actual_id, wanted_id, SUAUTHFILE));
142                         fputs (_("Password authentication bypassed.\n"),stderr);
143                         fclose (authfile_fd);
144                         return NOPWORD;
145                 } else if (!strcmp (action, "OWNPASS")) {
146                         SYSLOG ((su_to_root ? LOG_NOTICE : LOG_INFO,
147                                  "su from '%s' to '%s': asking for user's own password (%s)\n",
148                                  actual_id, wanted_id, SUAUTHFILE));
149                         fputs (_("Please enter your OWN password as authentication.\n"),
150                                stderr);
151                         fclose (authfile_fd);
152                         return OWNPWORD;
153                 } else {
154                         SYSLOG ((LOG_ERR,
155                                  "%s, line %d: unrecognised action!\n",
156                                  SUAUTHFILE, lines));
157                 }
158         }
159         fclose (authfile_fd);
160         return NOACTION;
161 }
162
163 static int applies (const char *single, char *list)
164 {
165         const char split[] = ", ";
166         char *tok;
167
168         int state = 0;
169
170         for (tok = strtok (list, split); tok != NULL;
171              tok = strtok (NULL, split)) {
172
173                 if (!strcmp (tok, "ALL")) {
174                         if (state != 0) {
175                                 SYSLOG ((LOG_ERR,
176                                          "%s, line %d: ALL in bad place\n",
177                                          SUAUTHFILE, lines));
178                                 return 0;
179                         }
180                         state = 1;
181                 } else if (!strcmp (tok, "EXCEPT")) {
182                         if (state != 1) {
183                                 SYSLOG ((LOG_ERR,
184                                          "%s, line %d: EXCEPT in bas place\n",
185                                          SUAUTHFILE, lines));
186                                 return 0;
187                         }
188                         state = 2;
189                 } else if (!strcmp (tok, "GROUP")) {
190                         if ((state != 0) && (state != 2)) {
191                                 SYSLOG ((LOG_ERR,
192                                          "%s, line %d: GROUP in bad place\n",
193                                          SUAUTHFILE, lines));
194                                 return 0;
195                         }
196                         state = (state == 0) ? 3 : 4;
197                 } else {
198                         switch (state) {
199                         case 0: /* No control words yet */
200                                 if (!strcmp (tok, single))
201                                         return 1;
202                                 break;
203                         case 1: /* An all */
204                                 SYSLOG ((LOG_ERR,
205                                          "%s, line %d: expect another token after ALL\n",
206                                          SUAUTHFILE, lines));
207                                 return 0;
208                         case 2: /* All except */
209                                 if (!strcmp (tok, single))
210                                         return 0;
211                                 break;
212                         case 3: /* Group */
213                                 if (isgrp (single, tok))
214                                         return 1;
215                                 break;
216                         case 4: /* All except group */
217                                 if (isgrp (single, tok))
218                                         return 0;
219                                 /* FALL THRU */
220                         }
221                 }
222         }
223         if ((state != 0) && (state != 3))
224                 return 1;
225         return 0;
226 }
227
228 static int isgrp (const char *name, const char *group)
229 {
230         struct group *grp;
231
232         grp = getgrnam (group); /* local, no need for xgetgrnam */
233
234         if (!grp || !grp->gr_mem)
235                 return 0;
236
237         return is_on_list (grp->gr_mem, name);
238 }
239 #endif                          /* SU_ACCESS */