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