1 /** Fichier db.c
2  **
3  ** Routines de gestion des mots de passe et des fichiers
4  ** de configuration pour calife.
5  **
6  ** Copyright (c) 1991-2010 by Ollivier ROBERT
7  ** A distribuer selon les regles de la GNU GPL General Public Licence
8  ** Voir le fichier COPYING fourni.
9  **
10  **/
11 
12 #ifndef lint
13 static const char * rcsid = "@(#) $Id$";
14 #endif
15 
16 #include "config.h"     /* GNU configure */
17 
18                         /* fichier de configuration */
19 #include "conf.h"
20 
21 static FILE * fp = NULL;    /* Moved from calife.c */
22 
23 /** On cherche et ouvre la database locale.
24  **
25  ** Dans tous les cas, le fichier log est ouvert (il est local). Si syslogd(8)
26  ** est actif on ouvre le "fichier" pour syslog(3). Le fichier de log devient
27  ** maintenant dependant de NO_SYSLOG: s'il n'y a pas de syslog d'utilisable
28  ** alors on ouvre le fichier de log.
29  **
30  ** Parametres :    neant
31  **
32  ** Retourne :      int     s'il y a un probleme renvoie 1 sinon 0.
33  **/
34 
35 int
open_databases(void)36 open_databases (void)
37 {
38     int err;
39 
40     MESSAGE ("Opening databases...\n");
41     /*
42      * become root again
43      */
44     GET_ROOT;
45 
46     /*
47      * open protected database
48      */
49     fp = fopen (AUTH_CONFIG_FILE, "r");
50     if (fp == NULL)
51     {
52         syslog (LOG_AUTH | LOG_ERR, "No database in `%s', launching su...\n", AUTH_CONFIG_FILE);
53         MESSAGE_1 ("No database in `%s'...\n", AUTH_CONFIG_FILE);
54         return 1;
55     }
56     else
57     {
58         /*
59          * XXX Is this still necessary?
60          */
61         err = fchmod (fileno (fp), 0400);
62         if (err)
63             die(6, "Unable to change '%s' permissions.", AUTH_CONFIG_FILE);
64             /*NOTREACHED*/
65     }
66     /*
67      * stay non root for a time
68      */
69     RELEASE_ROOT;
70     /*
71      * Success
72      */
73     return 0;
74 }
75 
76 /** Verifie si l'utilisateur de nom name a le droit d'utiliser
77  ** calife.
78  **
79  ** Line format is :
80  **
81  ** login[:][shell][:user1,user2,user3,...]
82  ** @group[:][shell][:user1,user2,...]
83  **
84  ** Parametres :    name        char *  nom de l'utilisateur
85  **                 user_to_be  char *  futur nom d'utilisateur
86  **
87  ** Retourne :      int     1 si l'utilisateur est autorise 0 sinon.
88  **/
89 
90 int
verify_auth_info(char * name,char * user_to_be)91 verify_auth_info (char * name, char * user_to_be)
92 {
93     int     allowed = 0;
94     char    ** user_list = NULL;
95     size_t  l_line = 0;
96     int     nb_users = 0;
97     char    * line, * ptr;
98     char    * line_name, * line_shell;
99     char    * group_name = NULL, * group = NULL, **p;
100     struct group *gr_group;
101 
102     /*
103      * let's search if user allowed or not
104      */
105 #ifdef HAVE_WORKING_SYSCONF
106     l_line = (size_t) sysconf (_SC_LINE_MAX);   /* returns long usually */
107 #else
108     l_line = MAX_STRING;
109 #endif /* HAVE_WORKING_SYSCONF */
110 
111     line = (char *) xalloc (l_line);
112     while (!feof (fp))
113     {
114         int lastc;
115 
116         if (fgets (line, l_line, fp) == NULL)
117             break;
118         /*
119          * remove trailing '\n' if present
120          */
121         lastc = strlen (line) - 1;
122         if (line [lastc] == '\n')
123             line [lastc] = '\0';
124         /*
125          * empty line or comment  or null login -- not allowed but ignored
126          */
127         if (!line || (*line) == '#' || (*line) == '\0')
128             continue;
129         MESSAGE_1 ("Line read = |%s|\n", line);
130         line_name = line;
131         /*
132          * Look for a @ or % as first character (for groups)
133          */
134         if (*line == '@' || *line == '%')
135         {
136             group = strdup(line);
137             group_name = strtok(group, ":");
138             group_name++;           /* skip '@' */
139             /*
140              *  Look into /etc/groups (or its equivalent with get)
141              */
142              gr_group = (struct group *) getgrnam(group_name);
143              if (gr_group == NULL)
144              {
145                  die(1, "No such group %s", group_name);
146                  allowed = 0;
147                  goto end;
148              }
149              for ( p = &gr_group->gr_mem[0]; *p ; p++ )
150              {
151                  MESSAGE_3 ("matching %s to %s in %s\n", name, *p, group_name);
152                  if (strcmp(name, *p) == 0)
153                  {
154                      MESSAGE_2 ("User %s Allowed through group %s\n", name, group_name);
155                      _group = strdup (group_name);
156                      strcpy (_group, group_name);
157                      allowed = 2;
158                      break;
159                  }
160              }
161         }
162         /*
163          * Look for first ':'
164          */
165         ptr = strchr (line, ':');
166         if (ptr == NULL)
167         {
168             /*
169              * No shell and no user list
170              */
171             custom_shell = 0;
172 
173             /*
174              * Bypass if already allowed through group
175              */
176             if (group_name != NULL && allowed == 1)
177                 goto escape;
178             if (strcmp (line_name, name))   /* not us */
179                 continue;
180             goto escape;
181         }
182         /*
183          * I got a ':', put a '\0' instead.
184          */
185         *ptr++ = '\0';
186         /*
187          * Do we have anything behind ?
188          */
189         if (*ptr == '\0')
190             custom_shell = 0;
191 
192         MESSAGE_2 ("Current line_name = |%s| / name = |%s|\n", line_name,name);
193 
194         /*
195          * Bypass if already allowed through group
196          */
197         if (group_name != NULL && allowed != 0)
198             goto end;
199         if (strcmp (line_name, name))   /* not us */
200             continue;
201 
202         line_shell = ptr;
203         /*
204          * Look for another ':', maybe just after the first one
205          */
206         ptr = strchr (line_shell, ':');
207         if (ptr == line_shell)
208             custom_shell = 0;
209         /*
210          * If we got another one, put a '\0' instead
211          */
212         if (ptr)
213             *ptr++ = '\0';
214         /*
215          * Analyze the shell candidate
216          */
217         if (*(line_shell) == '*')   /* LOCKED ACCOUNT */
218         {
219             allowed = 0;
220             goto end;
221         }
222         /*
223          * look for pathname
224          */
225         if (*(line_shell) == '/')
226         {
227             /*
228              * Is this a real shell ?
229              */
230             if (access (line_shell, R_OK | X_OK))
231             {
232                 MESSAGE_1 (" access of |%s| failed, no custom_shell\n",
233                            line_shell);
234                 custom_shell = 0;
235             }
236             else
237             {
238                 custom_shell = 1;
239                 shell = (char *) xalloc (strlen (line_shell) + 1);
240                 strncpy (shell, line_shell, strlen (line_shell));
241                 shell [strlen (line_shell)] = '\0';
242                 MESSAGE_1 (" current line_shell = |%s|\n", line_shell);
243             }
244         }
245         else
246         {
247             custom_shell = 0;
248         }
249         MESSAGE_1 (" custom_shell = |%d|\n", custom_shell);
250 
251         /*
252          * Analyze the rest of the line
253          */
254         if (ptr)
255         {
256             MESSAGE_1 ("ptr = %s\n", ptr);
257             /*
258              * we've got a user list
259              */
260             if (*ptr)
261             {
262                 char  * p, ** q;
263 
264                 MESSAGE_1 (" current user_list = |%s|\n", ptr);
265                 /*
266                  * the list should be user1,user2,...,user_n
267                  */
268                 p = ptr;     /* count users # in the list */
269                 while (p && *p)
270                     if (*p++ == ',')
271                         nb_users++;
272                 if (*--p != ',')    /* last char is not a ',' */
273                     nb_users++;
274 
275                 MESSAGE_1 ("  users # = |%d|\n", nb_users);
276 
277                 /*
278                  * two passes to avoid fixed size allocations
279                  */
280                 user_list = (char **) xalloc((nb_users + 1) * sizeof(char *));
281                 /*
282                  * put pointers in user_list
283                  */
284                 p = ptr;
285                 q = user_list;
286                 /*
287                  * 1st user is immediate
288                  */
289                 (*q++) = p;
290                 while (p && *p)
291                 {
292                     if (*p == ',')    /* found a ',' */
293                     {
294                         *p = '\0';
295                         if (*++p == ',')
296                             continue;
297                         (*q++) = p++;     /* next char is user name */
298                     }
299                     else
300                         p++;        /* only regular letters */
301                 }
302             }
303         }
304         /*
305          * user_list is complete, now compare
306          */
307 escape:
308         if (user_list)
309         {
310             int i;
311 
312             for ( i = 0; i < nb_users; i++ )
313             {
314                 MESSAGE_2(" comparing |%s| to |%s|\n",
315                           user_to_be, user_list [i]);
316                 if (!strcmp (user_list [i], user_to_be))
317                 {
318                     allowed = 1;
319                     goto end;   /* beuh but too many loops */
320                 }
321             }
322         }
323         else
324         {
325             allowed = 1;
326             break;
327         }
328     }
329 end:
330     free (line);
331     if (group)
332         free(group);
333     if (user_list)
334         free (user_list);
335     fclose (fp);
336     if (geteuid() == 0)
337         allowed = 1;
338     MESSAGE_1 ("Exit from verify_auth_info with allowed=%d\n", allowed);
339     return allowed;
340 }
341 
342