a4c981b16058b4caee8c97440f9fad53a7282895
[samba.git] / source3 / passdb / sampassdb.c
1 /* 
2    Unix SMB/Netbios implementation.
3    Version 1.9.
4    Password and authentication handling
5    Copyright (C) Jeremy Allison 1996-1998
6    Copyright (C) Luke Kenneth Casson Leighton 1996-1998
7       
8    This program is free software; you can redistribute it and/or modify
9    it under the terms of the GNU General Public License as published by
10    the Free Software Foundation; either version 2 of the License, or
11    (at your option) any later version.
12    
13    This program is distributed in the hope that it will be useful,
14    but WITHOUT ANY WARRANTY; without even the implied warranty of
15    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
16    GNU General Public License for more details.
17    
18    You should have received a copy of the GNU General Public License
19    along with this program; if not, write to the Free Software
20    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
21 */
22
23 #include "includes.h"
24 #include "nterr.h"
25
26 extern int DEBUGLEVEL;
27 extern DOM_SID global_sam_sid;
28
29 /*
30  * NOTE. All these functions are abstracted into a structure
31  * that points to the correct function for the selected database. JRA.
32  *
33  * NOTE.  for the get/mod/add functions, there are two sets of functions.
34  * one supports struct sam_passwd, the other supports struct smb_passwd.
35  * for speed optimisation it is best to support both these sets.
36  * 
37  * it is, however, optional to support one set but not the other: there
38  * is conversion-capability built in to passdb.c, and run-time error
39  * detection for when neither are supported.
40  * 
41  * password database writers are recommended to implement the sam_passwd
42  * functions in a first pass, as struct sam_passwd contains more
43  * information, needed by the NT Domain support.
44  * 
45  * an API writer is expected to create either one set (struct smb_passwd) or
46  * the other (struct sam_passwd) OR both, and optionally also to write display
47  * info routines * (struct sam_disp_info).  functions which the API writer
48  * chooses NOT to write must be wrapped in conversion functions (pwdb_x_to_y)
49  * such that API users can call any function and still get valid results.
50  *
51  * the password API does NOT fill in the gaps if you set an API function
52  * to NULL: it will deliberately attempt to call the NULL function.
53  *
54  */
55
56 static struct sam_passdb_ops *pwdb_ops;
57
58 /***************************************************************
59  Initialise the password db operations.
60 ***************************************************************/
61
62 BOOL initialise_sam_password_db(void)
63 {
64   if (pwdb_ops)
65   {
66     return True;
67   }
68
69 #ifdef WITH_NISPLUS
70   pwdb_ops =  nisplus_initialise_sam_password_db();
71 #elif defined(WITH_LDAP)
72   pwdb_ops = ldap_initialise_sam_password_db();
73 #elif defined(WITH_MYSQLSAM)
74   pwdb_ops = mysql_initialise_sam_password_db();
75 #elif defined(USE_SMBPASS_DB)
76   pwdb_ops = file_initialise_sam_password_db();
77 #endif 
78
79   return (pwdb_ops != NULL);
80 }
81
82 /*
83  * Functions that return/manipulate a struct sam_passwd.
84  */
85
86 /***************************************************************
87  Start to enumerate the smb or sam passwd list. Returns a void pointer
88  to ensure no modification outside this module.
89
90  Note that currently it is being assumed that a pointer returned
91  from this function may be used to enumerate struct sam_passwd
92  entries as well as struct smb_passwd entries. This may need
93  to change. JRA.
94
95 ****************************************************************/
96
97 void *startsam21pwent(BOOL update)
98 {
99   return pwdb_ops->startsam21pwent(update);
100 }
101
102 /***************************************************************
103  End enumeration of the sam passwd list.
104
105  Note that currently it is being assumed that a pointer returned
106  from this function may be used to enumerate struct sam_passwd
107  entries as well as struct smb_passwd entries. This may need
108  to change. JRA.
109
110 ****************************************************************/
111
112 void endsam21pwent(void *vp)
113 {
114   pwdb_ops->endsam21pwent(vp);
115 }
116
117 /*************************************************************************
118  Routine to return the next entry in the smb passwd list.
119  *************************************************************************/
120
121 struct sam_passwd *getsam21pwent(void *vp)
122 {
123         return pwdb_sam_map_names(pwdb_ops->getsam21pwent(vp));
124 }
125
126 /************************************************************************
127  Utility function to search sam passwd by name.  use this if your database
128  does not have search facilities.
129 *************************************************************************/
130
131 struct sam_passwd *iterate_getsam21pwntnam(const char *ntname)
132 {
133         fstring nt_name;
134         struct sam_passwd *pwd = NULL;
135         void *fp = NULL;
136
137         DEBUG(10, ("search by name: %s\n", ntname));
138
139         fstrcpy(nt_name, ntname);
140
141         /* Open the smb password database - not for update. */
142         fp = startsmbpwent(False);
143
144         if (fp == NULL)
145         {
146                 DEBUG(0, ("unable to open sam password database.\n"));
147                 return NULL;
148         }
149
150         while ((pwd = getsam21pwent(fp)) != NULL && !strequal(pwd->nt_name, nt_name))
151         {
152                 DEBUG(10, ("iterate: %s 0x%x\n", pwd->nt_name, pwd->user_rid));
153         }
154
155         if (pwd != NULL)
156         {
157                 DEBUG(10, ("found by name: %s\n", nt_name));
158         }
159
160         endsmbpwent(fp);
161         return pwd;
162 }
163
164 /************************************************************************
165  Utility function to search sam passwd by rid.  use this if your database
166  does not have search facilities.
167
168  search capability by both rid and uid are needed as the rid <-> uid
169  mapping may be non-monotonic.  
170
171 *************************************************************************/
172
173 struct sam_passwd *iterate_getsam21pwrid(uint32 rid)
174 {
175         struct sam_passwd *pwd = NULL;
176         void *fp = NULL;
177
178         DEBUG(10, ("search by rid: %x\n", rid));
179
180         /* Open the smb password file - not for update. */
181         fp = startsmbpwent(False);
182
183         if (fp == NULL)
184         {
185                 DEBUG(0, ("unable to open sam password database.\n"));
186                 return NULL;
187         }
188
189         while ((pwd = getsam21pwent(fp)) != NULL && pwd->user_rid != rid)
190         {
191                 DEBUG(10, ("iterate: %s 0x%x\n", pwd->nt_name, pwd->user_rid));
192         }
193
194         if (pwd != NULL)
195         {
196                 DEBUG(10, ("found by user_rid: %x\n", rid));
197         }
198
199         endsmbpwent(fp);
200         return pwd;
201 }
202
203 /************************************************************************
204  Utility function to search sam passwd by uid.  use this if your database
205  does not have search facilities.
206
207  search capability by both rid and uid are needed as the rid <-> uid
208  mapping may be non-monotonic.  
209
210 *************************************************************************/
211
212 struct sam_passwd *iterate_getsam21pwuid(uid_t uid)
213 {
214         struct sam_passwd *pwd = NULL;
215         void *fp = NULL;
216
217         DEBUG(10, ("search by uid: %x\n", (int)uid));
218
219         /* Open the smb password file - not for update. */
220         fp = startsmbpwent(False);
221
222         if (fp == NULL)
223         {
224                 DEBUG(0, ("unable to open sam password database.\n"));
225                 return NULL;
226         }
227
228         while ((pwd = getsam21pwent(fp)) != NULL && pwd->unix_uid != uid)
229         {
230         }
231
232         if (pwd != NULL)
233         {
234                 DEBUG(10, ("found by unix_uid: %x\n", (int)uid));
235         }
236
237         endsmbpwent(fp);
238         return pwd;
239 }
240
241 /*************************************************************************
242  Routine to return a display info structure, by rid
243  *************************************************************************/
244 struct sam_disp_info *getsamdisprid(uint32 rid)
245 {
246         return pwdb_ops->getsamdisprid(rid);
247 }
248
249 /************************************************************************
250  Routine to search sam passwd by name.
251 *************************************************************************/
252
253 struct sam_passwd *getsam21pwntnam(const char *name)
254 {
255         return pwdb_sam_map_names(pwdb_ops->getsam21pwntnam(name));
256 }
257
258 /************************************************************************
259  Routine to search sam passwd by rid.  
260 *************************************************************************/
261
262 struct sam_passwd *getsam21pwrid(uint32 rid)
263 {
264         return pwdb_sam_map_names(pwdb_ops->getsam21pwrid(rid));
265 }
266
267
268 /**********************************************************
269  **********************************************************
270
271  utility routines which are likely to be useful to all password
272  databases
273
274  **********************************************************
275  **********************************************************/
276
277 /*************************************************************
278  initialises a struct sam_disp_info.
279  **************************************************************/
280
281 static void pwdb_init_dispinfo(struct sam_disp_info *user)
282 {
283         if (user == NULL) return;
284         bzero(user, sizeof(*user));
285         user->user_rid = 0xffffffff;
286 }
287
288 /*************************************************************
289  initialises a struct sam_passwd.
290  **************************************************************/
291 void pwdb_init_sam(struct sam_passwd *user)
292 {
293         if (user == NULL) return;
294         bzero(user, sizeof(*user));
295
296         init_nt_time(&user->logon_time);
297         init_nt_time(&user->logoff_time);
298         init_nt_time(&user->kickoff_time);
299         init_nt_time(&user->pass_last_set_time);
300         init_nt_time(&user->pass_can_change_time);
301         init_nt_time(&user->pass_must_change_time);
302
303         user->unix_uid = (uid_t)-1;
304         user->unix_gid = (gid_t)-1;
305         user->user_rid  = 0xffffffff;
306         user->group_rid = 0xffffffff;
307 }
308
309 /*************************************************************************
310  Routine to return the next entry in the sam passwd list.
311  *************************************************************************/
312
313 struct sam_disp_info *pwdb_sam_to_dispinfo(struct sam_passwd *user)
314 {
315         static struct sam_disp_info disp_info;
316
317         if (user == NULL) return NULL;
318
319         pwdb_init_dispinfo(&disp_info);
320
321         disp_info.nt_name   = user->nt_name;
322         disp_info.full_name = user->full_name;
323         disp_info.user_rid  = user->user_rid;
324
325         return &disp_info;
326 }
327
328 /*************************************************************
329  converts a sam_passwd structure to a smb_passwd structure.
330  **************************************************************/
331
332 struct smb_passwd *pwdb_sam_to_smb(struct sam_passwd *user)
333 {
334         static struct smb_passwd pw_buf;
335         static fstring nt_name;
336         static fstring unix_name;
337
338         if (user == NULL) return NULL;
339
340         pwdb_init_smb(&pw_buf);
341
342         if (user->nt_name != NULL)
343         {
344                 fstrcpy(nt_name  , user->nt_name);
345                 pw_buf.nt_name = nt_name;
346         }
347         if (user->unix_name != NULL)
348         {
349                 fstrcpy(unix_name, user->unix_name);
350                 pw_buf.unix_name = unix_name;
351         }
352         pw_buf.unix_uid           = user->unix_uid;
353         pw_buf.user_rid           = user->user_rid;
354         pw_buf.smb_passwd         = user->smb_passwd;
355         pw_buf.smb_nt_passwd      = user->smb_nt_passwd;
356         pw_buf.acct_ctrl          = user->acct_ctrl;
357         pw_buf.pass_last_set_time = nt_time_to_unix(&user->pass_last_set_time);
358
359         return &pw_buf;
360 }
361
362
363 /*************************************************************
364  converts a smb_passwd structure to a sam_passwd structure.
365  **************************************************************/
366
367 struct sam_passwd *pwdb_smb_to_sam(struct smb_passwd *user)
368 {
369         static struct sam_passwd pw_buf;
370         static fstring nt_name;
371         static fstring unix_name;
372
373         if (user == NULL) return NULL;
374
375         pwdb_init_sam(&pw_buf);
376
377         if (user->nt_name != NULL)
378         {
379                 fstrcpy(nt_name  , user->nt_name);
380                 pw_buf.nt_name = nt_name;
381         }
382         if (user->unix_name != NULL)
383         {
384                 fstrcpy(unix_name, user->unix_name);
385                 pw_buf.unix_name = unix_name;
386         }
387         pw_buf.unix_uid           = user->unix_uid;
388         pw_buf.user_rid           = user->user_rid;
389         pw_buf.smb_passwd         = user->smb_passwd;
390         pw_buf.smb_nt_passwd      = user->smb_nt_passwd;
391         pw_buf.acct_ctrl          = user->acct_ctrl;
392
393         if ( user->pass_last_set_time != (time_t)-1 )
394         {
395                 unix_to_nt_time(&pw_buf.pass_last_set_time, user->pass_last_set_time);
396                 unix_to_nt_time(&pw_buf.pass_can_change_time, user->pass_last_set_time);
397         }
398
399         return &pw_buf;
400 }
401
402 static BOOL trust_account_warning_done = False;
403
404 /*************************************************************
405  fills in missing details.  one set of details _must_ exist.
406  **************************************************************/
407 struct sam_passwd *pwdb_sam_map_names(struct sam_passwd *sam)
408 {
409         DOM_NAME_MAP gmep;
410         BOOL found = False;
411         DOM_SID sid;
412         static fstring unix_name;
413         static fstring nt_name;
414
415         DEBUG(10,("pwdb_sam_map_names\n"));
416
417         /*
418          * name details
419          */
420
421         if (sam == NULL)
422         {
423                 return NULL;
424         }
425
426         if (!found && sam->unix_name != NULL)
427         {
428                 found = lookupsmbpwnam(sam->unix_name, &gmep);
429         }
430         if (!found && sam->unix_uid  != (uid_t)-1)
431         {
432                 found = lookupsmbpwuid(sam->unix_uid , &gmep);
433         }
434         if (!found && sam->user_rid != 0xffffffff)
435         {
436                 sid_copy(&sid, &global_sam_sid);
437                 sid_append_rid(&sid, sam->user_rid);
438                 found = lookupsmbpwsid  (&sid        , &gmep);
439         }
440         if (!found && sam->nt_name  != NULL)
441         {
442                 found = lookupsmbpwntnam(sam->nt_name, &gmep);
443         }
444
445         if (!found)
446         {
447                 return NULL;
448         }
449
450         if (!sid_front_equal(&global_sam_sid, &gmep.sid))
451         {
452                 return NULL;
453         }
454
455         fstrcpy(unix_name, gmep.unix_name);
456         fstrcpy(nt_name  , gmep.nt_name  );
457         if (sam->unix_name == NULL      ) sam->unix_name = unix_name;
458         if (sam->nt_name   == NULL      ) sam->nt_name   = nt_name  ;
459         if (sam->unix_uid  == (uid_t)-1 ) sam->unix_uid  = (uid_t)gmep.unix_id;
460         if (sam->user_rid  == 0xffffffff) sid_split_rid(&gmep.sid, &sam->user_rid);
461
462         DEBUG(10,("pwdb_sam_map_name: found unix user %s nt %s uid %d rid 0x%x\n",
463                    sam->unix_name, sam->nt_name, sam->unix_uid, sam->user_rid));
464
465         /*
466          * group details
467          */
468
469         found = False;
470
471         if (sam->unix_gid != (gid_t)-1 && sam->group_rid != 0xffffffff)
472         {
473                 return sam;
474         }
475
476         if (sam->unix_gid == (gid_t)-1 && sam->group_rid == 0xffffffff)
477         {
478                 struct passwd *pass = getpwnam(unix_name);
479                 if (pass != NULL)
480                 {
481                         sam->unix_gid = pass->pw_gid;
482                 }
483                 else
484                 {
485                         DEBUG(0,("pwdb_sam_map_names: no unix password entry for %s\n",
486                                   unix_name));
487                 }
488         }
489
490         if (!found && sam->unix_gid  != (gid_t)-1)
491         {
492                 found = lookupsmbgrpgid(sam->unix_gid , &gmep);
493         }
494         if (!found && sam->group_rid != 0xffffffff)
495         {
496                 sid_copy(&sid, &global_sam_sid);
497                 sid_append_rid(&sid, sam->group_rid);
498                 found = lookupsmbgrpsid(&sid        , &gmep);
499         }
500
501         if (!found)
502         {
503                 if (IS_BITS_SET_SOME(sam->acct_ctrl, ACB_WSTRUST|ACB_DOMTRUST|ACB_SVRTRUST))
504                 {
505                         if (!trust_account_warning_done)
506                         {
507                                 trust_account_warning_done = True;
508                                 DEBUG(0, ("\
509 pwdb_sam_map_names: your unix password database appears to have difficulties\n\
510 resolving trust account %s, probably because it ends in a '$'.\n\
511 you will get this warning only once (for all trust accounts)\n", unix_name));
512                         }
513                         /*
514                          * oh, dear.
515                          */
516                         if (sam->unix_gid != (gid_t)-1)
517                         {
518                                 sam->unix_gid = (gid_t)-1;
519                         }
520                         sam->group_rid = DOMAIN_GROUP_RID_USERS;
521
522                         return sam;
523                 }
524                 else
525                 {
526                         DEBUG(0, ("pwdb_sam_map_names: could not find Primary Group for %s\n",
527                                    unix_name));
528                         return NULL;
529                 }
530         }
531
532         if (!sid_front_equal(&global_sam_sid, &gmep.sid))
533         {
534                 fstring sid_str;
535                 sid_to_string(sid_str, &gmep.sid);
536                 DEBUG(0,("UNIX User %s Primary Group is in the wrong domain! %s\n",
537                           sam->unix_name, sid_str));
538                 return NULL;
539         }
540
541         if (sam->unix_gid  == (gid_t)-1 ) sam->unix_gid  = (gid_t)gmep.unix_id;
542         if (sam->group_rid == 0xffffffff) sid_split_rid(&gmep.sid, &sam->group_rid);
543
544         DEBUG(10,("pwdb_sam_map_name: found gid %d and group rid 0x%x for unix user %s\n",
545                    sam->unix_gid, sam->group_rid, sam->unix_name));
546
547         return sam;
548 }