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