Fixed the "You password will expire in 0 days. Would you like to
[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(USE_SMBPASS_DB)
74   pwdb_ops = file_initialise_sam_password_db();
75 #endif 
76
77   return (pwdb_ops != NULL);
78 }
79
80 /*
81  * Functions that return/manipulate a struct sam_passwd.
82  */
83
84 /***************************************************************
85  Start to enumerate the smb or sam passwd list. Returns a void pointer
86  to ensure no modification outside this module.
87
88  Note that currently it is being assumed that a pointer returned
89  from this function may be used to enumerate struct sam_passwd
90  entries as well as struct smb_passwd entries. This may need
91  to change. JRA.
92
93 ****************************************************************/
94
95 void *startsam21pwent(BOOL update)
96 {
97   return pwdb_ops->startsam21pwent(update);
98 }
99
100 /***************************************************************
101  End enumeration of the sam passwd list.
102
103  Note that currently it is being assumed that a pointer returned
104  from this function may be used to enumerate struct sam_passwd
105  entries as well as struct smb_passwd entries. This may need
106  to change. JRA.
107
108 ****************************************************************/
109
110 void endsam21pwent(void *vp)
111 {
112   pwdb_ops->endsam21pwent(vp);
113 }
114
115 /*************************************************************************
116  Routine to return the next entry in the smb passwd list.
117  *************************************************************************/
118
119 struct sam_passwd *getsam21pwent(void *vp)
120 {
121         return pwdb_sam_map_names(pwdb_ops->getsam21pwent(vp));
122 }
123
124 /************************************************************************
125  Utility function to search sam passwd by name.  use this if your database
126  does not have search facilities.
127 *************************************************************************/
128
129 struct sam_passwd *iterate_getsam21pwntnam(const char *ntname)
130 {
131         fstring nt_name;
132         struct sam_passwd *pwd = NULL;
133         void *fp = NULL;
134
135         DEBUG(10, ("search by name: %s\n", ntname));
136
137         fstrcpy(nt_name, ntname);
138
139         /* Open the smb password database - not for update. */
140         fp = startsmbpwent(False);
141
142         if (fp == NULL)
143         {
144                 DEBUG(0, ("unable to open sam password database.\n"));
145                 return NULL;
146         }
147
148         while ((pwd = getsam21pwent(fp)) != NULL && !strequal(pwd->nt_name, nt_name))
149         {
150                 DEBUG(10, ("iterate: %s 0x%x\n", pwd->nt_name, pwd->user_rid));
151         }
152
153         if (pwd != NULL)
154         {
155                 DEBUG(10, ("found by name: %s\n", nt_name));
156         }
157
158         endsmbpwent(fp);
159         return pwd;
160 }
161
162 /************************************************************************
163  Utility function to search sam passwd by rid.  use this if your database
164  does not have search facilities.
165
166  search capability by both rid and uid are needed as the rid <-> uid
167  mapping may be non-monotonic.  
168
169 *************************************************************************/
170
171 struct sam_passwd *iterate_getsam21pwrid(uint32 rid)
172 {
173         struct sam_passwd *pwd = NULL;
174         void *fp = NULL;
175
176         DEBUG(10, ("search by rid: %x\n", rid));
177
178         /* Open the smb password file - not for update. */
179         fp = startsmbpwent(False);
180
181         if (fp == NULL)
182         {
183                 DEBUG(0, ("unable to open sam password database.\n"));
184                 return NULL;
185         }
186
187         while ((pwd = getsam21pwent(fp)) != NULL && pwd->user_rid != rid)
188         {
189                 DEBUG(10, ("iterate: %s 0x%x\n", pwd->nt_name, pwd->user_rid));
190         }
191
192         if (pwd != NULL)
193         {
194                 DEBUG(10, ("found by user_rid: %x\n", rid));
195         }
196
197         endsmbpwent(fp);
198         return pwd;
199 }
200
201 /************************************************************************
202  Utility function to search sam passwd by uid.  use this if your database
203  does not have search facilities.
204
205  search capability by both rid and uid are needed as the rid <-> uid
206  mapping may be non-monotonic.  
207
208 *************************************************************************/
209
210 struct sam_passwd *iterate_getsam21pwuid(uid_t uid)
211 {
212         struct sam_passwd *pwd = NULL;
213         void *fp = NULL;
214
215         DEBUG(10, ("search by uid: %x\n", (int)uid));
216
217         /* Open the smb password file - not for update. */
218         fp = startsmbpwent(False);
219
220         if (fp == NULL)
221         {
222                 DEBUG(0, ("unable to open sam password database.\n"));
223                 return NULL;
224         }
225
226         while ((pwd = getsam21pwent(fp)) != NULL && pwd->unix_uid != uid)
227         {
228         }
229
230         if (pwd != NULL)
231         {
232                 DEBUG(10, ("found by unix_uid: %x\n", (int)uid));
233         }
234
235         endsmbpwent(fp);
236         return pwd;
237 }
238
239 /*************************************************************************
240  Routine to return a display info structure, by rid
241  *************************************************************************/
242 struct sam_disp_info *getsamdisprid(uint32 rid)
243 {
244         return pwdb_ops->getsamdisprid(rid);
245 }
246
247 /************************************************************************
248  Routine to search sam passwd by name.
249 *************************************************************************/
250
251 struct sam_passwd *getsam21pwntnam(const char *name)
252 {
253         return pwdb_sam_map_names(pwdb_ops->getsam21pwntnam(name));
254 }
255
256 /************************************************************************
257  Routine to search sam passwd by rid.  
258 *************************************************************************/
259
260 struct sam_passwd *getsam21pwrid(uint32 rid)
261 {
262         return pwdb_sam_map_names(pwdb_ops->getsam21pwrid(rid));
263 }
264
265
266 /**********************************************************
267  **********************************************************
268
269  utility routines which are likely to be useful to all password
270  databases
271
272  **********************************************************
273  **********************************************************/
274
275 /*************************************************************
276  initialises a struct sam_disp_info.
277  **************************************************************/
278
279 static void pwdb_init_dispinfo(struct sam_disp_info *user)
280 {
281         if (user == NULL) return;
282         bzero(user, sizeof(*user));
283         user->user_rid = 0xffffffff;
284 }
285
286 /*************************************************************
287  initialises a struct sam_passwd.
288  **************************************************************/
289 void pwdb_init_sam(struct sam_passwd *user)
290 {
291         if (user == NULL) return;
292         bzero(user, sizeof(*user));
293         unix_to_nt_time(&user->logon_time            , (time_t)-1);
294         unix_to_nt_time(&user->logoff_time           , (time_t)-1);
295         unix_to_nt_time(&user->kickoff_time          , (time_t)-1);
296         unix_to_nt_time(&user->pass_last_set_time    , (time_t)-1);
297         unix_to_nt_time(&user->pass_can_change_time  , (time_t)-1);
298         unix_to_nt_time(&user->pass_must_change_time , (time_t)-1);
299
300         user->unix_uid = (uid_t)-1;
301         user->unix_gid = (gid_t)-1;
302         user->user_rid  = 0xffffffff;
303         user->group_rid = 0xffffffff;
304 }
305
306 /*************************************************************************
307  Routine to return the next entry in the sam passwd list.
308  *************************************************************************/
309
310 struct sam_disp_info *pwdb_sam_to_dispinfo(struct sam_passwd *user)
311 {
312         static struct sam_disp_info disp_info;
313
314         if (user == NULL) return NULL;
315
316         pwdb_init_dispinfo(&disp_info);
317
318         disp_info.nt_name   = user->nt_name;
319         disp_info.full_name = user->full_name;
320         disp_info.user_rid  = user->user_rid;
321
322         return &disp_info;
323 }
324
325 /*************************************************************
326  converts a sam_passwd structure to a smb_passwd structure.
327  **************************************************************/
328
329 struct smb_passwd *pwdb_sam_to_smb(struct sam_passwd *user)
330 {
331         static struct smb_passwd pw_buf;
332         static fstring nt_name;
333         static fstring unix_name;
334
335         if (user == NULL) return NULL;
336
337         pwdb_init_smb(&pw_buf);
338
339         fstrcpy(nt_name  , user->nt_name);
340         fstrcpy(unix_name, user->unix_name);
341         pw_buf.nt_name            = nt_name;
342         pw_buf.unix_name          = unix_name;
343         pw_buf.unix_uid           = user->unix_uid;
344         pw_buf.user_rid           = user->user_rid;
345         pw_buf.smb_passwd         = user->smb_passwd;
346         pw_buf.smb_nt_passwd      = user->smb_nt_passwd;
347         pw_buf.acct_ctrl          = user->acct_ctrl;
348         pw_buf.pass_last_set_time = nt_time_to_unix(&user->pass_last_set_time);
349
350         return &pw_buf;
351 }
352
353
354 /*************************************************************
355  converts a smb_passwd structure to a sam_passwd structure.
356  **************************************************************/
357
358 struct sam_passwd *pwdb_smb_to_sam(struct smb_passwd *user)
359 {
360         static struct sam_passwd pw_buf;
361         static fstring nt_name;
362         static fstring unix_name;
363         static time_t t;
364         static int time_count = 0;
365
366         if (user == NULL) return NULL;
367
368         pwdb_init_sam(&pw_buf);
369
370         fstrcpy(nt_name  , user->nt_name);
371         fstrcpy(unix_name, user->unix_name);
372         pw_buf.nt_name            = nt_name;
373         pw_buf.unix_name          = unix_name;
374         pw_buf.unix_uid           = user->unix_uid;
375         pw_buf.user_rid           = user->user_rid;
376         pw_buf.smb_passwd         = user->smb_passwd;
377         pw_buf.smb_nt_passwd      = user->smb_nt_passwd;
378         pw_buf.acct_ctrl          = user->acct_ctrl;
379
380         /* Just update the time counter every 1,000 times though this function */
381         switch (time_count) {
382                 case 0: 
383                         DEBUG(3, ("Called time() in smb_to_sam function\n"));
384                         time (&t);
385                         time_count++;
386                         break;
387                 case 1000:
388                         time_count = 0;
389                         break;
390                 default:
391                         time_count++;
392                         break;
393         }
394
395         if ( user->pass_last_set_time == (time_t)-1 )
396         {
397                 user->pass_last_set_time = t;
398         }
399         unix_to_nt_time(&pw_buf.pass_last_set_time, user->pass_last_set_time);
400         unix_to_nt_time(&pw_buf.pass_can_change_time , user->pass_last_set_time);
401         unix_to_nt_time(&pw_buf.pass_must_change_time, t+3628800);
402
403
404         return &pw_buf;
405 }
406
407 static BOOL trust_account_warning_done = False;
408
409 /*************************************************************
410  fills in missing details.  one set of details _must_ exist.
411  **************************************************************/
412 struct sam_passwd *pwdb_sam_map_names(struct sam_passwd *sam)
413 {
414         DOM_NAME_MAP gmep;
415         BOOL found = False;
416         DOM_SID sid;
417         static fstring unix_name;
418         static fstring nt_name;
419
420         DEBUG(10,("pwdb_sam_map_names\n"));
421
422         /*
423          * name details
424          */
425
426         if (sam == NULL)
427         {
428                 return NULL;
429         }
430
431         if (!found && sam->unix_name != NULL)
432         {
433                 found = lookupsmbpwnam(sam->unix_name, &gmep);
434         }
435         if (!found && sam->unix_uid  != (uid_t)-1)
436         {
437                 found = lookupsmbpwuid(sam->unix_uid , &gmep);
438         }
439         if (!found && sam->user_rid != 0xffffffff)
440         {
441                 sid_copy(&sid, &global_sam_sid);
442                 sid_append_rid(&sid, sam->user_rid);
443                 found = lookupsmbpwsid  (&sid        , &gmep);
444         }
445         if (!found && sam->nt_name  != NULL)
446         {
447                 found = lookupsmbpwntnam(sam->nt_name, &gmep);
448         }
449
450         if (!found)
451         {
452                 return NULL;
453         }
454
455         if (!sid_front_equal(&global_sam_sid, &gmep.sid))
456         {
457                 return NULL;
458         }
459
460         fstrcpy(unix_name, gmep.unix_name);
461         fstrcpy(nt_name  , gmep.nt_name  );
462         if (sam->unix_name == NULL      ) sam->unix_name = unix_name;
463         if (sam->nt_name   == NULL      ) sam->nt_name   = nt_name  ;
464         if (sam->unix_uid  == (uid_t)-1 ) sam->unix_uid  = (uid_t)gmep.unix_id;
465         if (sam->user_rid  == 0xffffffff) sid_split_rid(&gmep.sid, &sam->user_rid);
466
467         DEBUG(10,("pwdb_sam_map_name: found unix user %s nt %s uid %d rid 0x%x\n",
468                    sam->unix_name, sam->nt_name, sam->unix_uid, sam->user_rid));
469
470         /*
471          * group details
472          */
473
474         found = False;
475
476         if (sam->unix_gid != (gid_t)-1 && sam->group_rid != 0xffffffff)
477         {
478                 return sam;
479         }
480
481         if (sam->unix_gid == (gid_t)-1 && sam->group_rid == 0xffffffff)
482         {
483                 struct passwd *pass = getpwnam(unix_name);
484                 if (pass != NULL)
485                 {
486                         sam->unix_gid = pass->pw_gid;
487                 }
488                 else
489                 {
490                         DEBUG(0,("pwdb_sam_map_names: no unix password entry for %s\n",
491                                   unix_name));
492                 }
493         }
494
495         if (!found && sam->unix_gid  != (gid_t)-1)
496         {
497                 found = lookupsmbgrpgid(sam->unix_gid , &gmep);
498         }
499         if (!found && sam->group_rid != 0xffffffff)
500         {
501                 sid_copy(&sid, &global_sam_sid);
502                 sid_append_rid(&sid, sam->group_rid);
503                 found = lookupsmbgrpsid(&sid        , &gmep);
504         }
505
506         if (!found)
507         {
508                 if (IS_BITS_SET_SOME(sam->acct_ctrl, ACB_WSTRUST|ACB_DOMTRUST|ACB_SVRTRUST))
509                 {
510                         if (!trust_account_warning_done)
511                         {
512                                 trust_account_warning_done = True;
513                                 DEBUG(0, ("\
514 pwdb_sam_map_names: your unix password database appears to have difficulties\n\
515 resolving trust account %s, probably because it ends in a '$'.\n\
516 you will get this warning only once (for all trust accounts)\n", unix_name));
517                         }
518                         /*
519                          * oh, dear.
520                          */
521                         if (sam->unix_gid != (gid_t)-1)
522                         {
523                                 sam->unix_gid = (gid_t)-1;
524                         }
525                         sam->group_rid = DOMAIN_GROUP_RID_USERS;
526
527                         return sam;
528                 }
529                 else
530                 {
531                         DEBUG(0, ("pwdb_sam_map_names: could not find Primary Group for %s\n",
532                                    unix_name));
533                         return NULL;
534                 }
535         }
536
537         if (!sid_front_equal(&global_sam_sid, &gmep.sid))
538         {
539                 fstring sid_str;
540                 sid_to_string(sid_str, &gmep.sid);
541                 DEBUG(0,("UNIX User %s Primary Group is in the wrong domain! %s\n",
542                           sam->unix_name, sid_str));
543                 return NULL;
544         }
545
546         if (sam->unix_gid  == (gid_t)-1 ) sam->unix_gid  = (gid_t)gmep.unix_id;
547         if (sam->group_rid == 0xffffffff) sid_split_rid(&gmep.sid, &sam->group_rid);
548
549         DEBUG(10,("pwdb_sam_map_name: found gid %d and group rid 0x%x for unix user %s\n",
550                    sam->unix_gid, sam->group_rid, sam->unix_name));
551
552         return sam;
553 }