updated the 3.0 branch from the head branch - ready for alpha18
[kai/samba.git] / source3 / auth / auth_rhosts.c
1 /* 
2    Unix SMB/CIFS implementation.
3    Main SMB reply routines
4    Copyright (C) Andrew Tridgell 1992-1998
5    
6    This program is free software; you can redistribute it and/or modify
7    it under the terms of the GNU General Public License as published by
8    the Free Software Foundation; either version 2 of the License, or
9    (at your option) any later version.
10    
11    This program is distributed in the hope that it will be useful,
12    but WITHOUT ANY WARRANTY; without even the implied warranty of
13    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14    GNU General Public License for more details.
15    
16    You should have received a copy of the GNU General Public License
17    along with this program; if not, write to the Free Software
18    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
19 */
20
21 #include "includes.h"
22
23 #undef DBGC_CLASS
24 #define DBGC_CLASS DBGC_AUTH
25
26 /****************************************************************************
27  Read the a hosts.equiv or .rhosts file and check if it
28  allows this user from this machine.
29 ****************************************************************************/
30
31 static BOOL check_user_equiv(const char *user, const char *remote, const char *equiv_file)
32 {
33   int plus_allowed = 1;
34   char *file_host;
35   char *file_user;
36   char **lines = file_lines_load(equiv_file, NULL);
37   int i;
38
39   DEBUG(5, ("check_user_equiv %s %s %s\n", user, remote, equiv_file));
40   if (! lines) return False;
41   for (i=0; lines[i]; i++) {
42     char *buf = lines[i];
43     trim_string(buf," "," ");
44
45     if (buf[0] != '#' && buf[0] != '\n') 
46     {
47       BOOL is_group = False;
48       int plus = 1;
49       char *bp = buf;
50       if (strcmp(buf, "NO_PLUS\n") == 0)
51       {
52         DEBUG(6, ("check_user_equiv NO_PLUS\n"));
53         plus_allowed = 0;
54       }
55       else {
56         if (buf[0] == '+') 
57         {
58           bp++;
59           if (*bp == '\n' && plus_allowed) 
60           {
61             /* a bare plus means everbody allowed */
62             DEBUG(6, ("check_user_equiv everybody allowed\n"));
63             file_lines_free(lines);
64             return True;
65           }
66         }
67         else if (buf[0] == '-')
68         {
69           bp++;
70           plus = 0;
71         }
72         if (*bp == '@') 
73         {
74           is_group = True;
75           bp++;
76         }
77         file_host = strtok(bp, " \t\n");
78         file_user = strtok(NULL, " \t\n");
79         DEBUG(7, ("check_user_equiv %s %s\n", file_host ? file_host : "(null)", 
80                  file_user ? file_user : "(null)" ));
81         if (file_host && *file_host) 
82         {
83           BOOL host_ok = False;
84
85 #if defined(HAVE_NETGROUP) && defined(HAVE_YP_GET_DEFAULT_DOMAIN)
86           if (is_group)
87             {
88               static char *mydomain = NULL;
89               if (!mydomain)
90                 yp_get_default_domain(&mydomain);
91               if (mydomain && innetgr(file_host,remote,user,mydomain))
92                 host_ok = True;
93             }
94 #else
95           if (is_group)
96             {
97               DEBUG(1,("Netgroups not configured\n"));
98               continue;
99             }
100 #endif
101
102           /* is it this host */
103           /* the fact that remote has come from a call of gethostbyaddr
104            * means that it may have the fully qualified domain name
105            * so we could look up the file version to get it into
106            * a canonical form, but I would rather just type it
107            * in full in the equiv file
108            */
109           if (!host_ok && !is_group && strequal(remote, file_host))
110             host_ok = True;
111
112           if (!host_ok)
113             continue;
114
115           /* is it this user */
116           if (file_user == 0 || strequal(user, file_user)) 
117             {
118               DEBUG(5, ("check_user_equiv matched %s%s %s\n",
119                         (plus ? "+" : "-"), file_host,
120                         (file_user ? file_user : "")));
121               file_lines_free(lines);
122               return (plus ? True : False);
123             }
124         }
125       }
126     }
127   }
128   file_lines_free(lines);
129   return False;
130 }
131
132
133 /****************************************************************************
134 check for a possible hosts equiv or rhosts entry for the user
135 ****************************************************************************/
136
137 static BOOL check_hosts_equiv(struct passwd *pass)
138 {
139   char *fname = NULL;
140
141   if (!pass) 
142     return(False);
143
144   fname = lp_hosts_equiv();
145
146   /* note: don't allow hosts.equiv on root */
147   if (fname && *fname && (pass->pw_uid != 0)) {
148           if (check_user_equiv(pass->pw_name,client_name(),fname))
149                   return(True);
150   }
151   
152   return(False);
153 }
154
155
156 /****************************************************************************
157  Check for a valid .rhosts/hosts.equiv entry for this user
158 ****************************************************************************/
159
160 static NTSTATUS check_hostsequiv_security(const struct auth_context *auth_context,
161                                           void *my_private_data, 
162                                           TALLOC_CTX *mem_ctx,
163                                           const auth_usersupplied_info *user_info, 
164                                           auth_serversupplied_info **server_info)
165 {
166         NTSTATUS nt_status = NT_STATUS_LOGON_FAILURE;
167         struct passwd *pass = Get_Pwnam(user_info->internal_username.str);
168         
169         if (pass) {
170                 if (check_hosts_equiv(pass)) {
171                         nt_status = NT_STATUS_OK;
172                         make_server_info_pw(server_info, pass);
173                 }
174         } else {
175                 nt_status = NT_STATUS_NO_SUCH_USER;
176         }
177
178         return nt_status;
179 }
180
181 /* module initialisation */
182 NTSTATUS auth_init_hostsequiv(struct auth_context *auth_context, const char* param, auth_methods **auth_method) 
183 {
184         if (!make_auth_methods(auth_context, auth_method)) {
185                 return NT_STATUS_NO_MEMORY;
186         }
187
188         (*auth_method)->auth = check_hostsequiv_security;
189         return NT_STATUS_OK;
190 }
191
192
193 /****************************************************************************
194  Check for a valid .rhosts/hosts.equiv entry for this user
195 ****************************************************************************/
196
197 static NTSTATUS check_rhosts_security(const struct auth_context *auth_context,
198                                       void *my_private_data, 
199                                       TALLOC_CTX *mem_ctx,
200                                       const auth_usersupplied_info *user_info, 
201                                       auth_serversupplied_info **server_info)
202 {
203         NTSTATUS nt_status = NT_STATUS_LOGON_FAILURE;
204         struct passwd *pass = Get_Pwnam(user_info->internal_username.str);
205         pstring rhostsfile;
206         
207         if (pass) {
208                 char *home = pass->pw_dir;
209                 if (home) {
210                         slprintf(rhostsfile, sizeof(rhostsfile)-1, "%s/.rhosts", home);
211                         become_root();
212                         if (check_user_equiv(pass->pw_name,client_name(),rhostsfile)) {
213                                 nt_status = NT_STATUS_OK;
214                                 make_server_info_pw(server_info, pass);
215                         }
216                         unbecome_root();
217                 } 
218         } else {
219                 nt_status = NT_STATUS_NO_SUCH_USER;
220         }
221
222         return nt_status;
223 }
224
225 /* module initialisation */
226 NTSTATUS auth_init_rhosts(struct auth_context *auth_context, const char *param, auth_methods **auth_method) 
227 {
228         if (!make_auth_methods(auth_context, auth_method)) {
229                 return NT_STATUS_NO_MEMORY;
230         }
231
232         (*auth_method)->auth = check_rhosts_security;
233         return NT_STATUS_OK;
234 }