d5b395a0a180ba35bd6bfb5923824f82b1154363
[kai/samba.git] / source / 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(HAVE_MYSQL_H) && 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  Routine to search the smb passwd file for an entry matching the username.
128  and then modify its password entry. We can't use the startsampwent()/
129  getsampwent()/endsampwent() interfaces here as we depend on looking
130  in the actual file to decide how much room we have to write data.
131  override = False, normal
132  override = True, override XXXXXXXX'd out password or NO PASS
133 ************************************************************************/
134
135 BOOL mod_sam21pwd_entry(struct sam_passwd* pwd, BOOL override)
136 {
137         DEBUG(10,("mod_sam21pwd_entry: unix user %s rid %d\n", 
138                 pwd->unix_name, pwd->user_rid));
139
140         return pwdb_ops->mod_sam21pwd_entry(pwdb_sam_map_names(pwd), override);
141 }
142
143 /************************************************************************
144  Utility function to search sam passwd by name.  use this if your database
145  does not have search facilities.
146 *************************************************************************/
147
148 struct sam_passwd *iterate_getsam21pwntnam(const char *ntname)
149 {
150         fstring nt_name;
151         struct sam_passwd *pwd = NULL;
152         void *fp = NULL;
153
154         DEBUG(10, ("search by name: %s\n", ntname));
155
156         fstrcpy(nt_name, ntname);
157
158         /* Open the smb password database - not for update. */
159         fp = startsmbpwent(False);
160
161         if (fp == NULL)
162         {
163                 DEBUG(0, ("unable to open sam password database.\n"));
164                 return NULL;
165         }
166
167         while ((pwd = getsam21pwent(fp)) != NULL && !strequal(pwd->nt_name, nt_name))
168         {
169                 DEBUG(10, ("iterate: %s 0x%x\n", pwd->nt_name, pwd->user_rid));
170         }
171
172         if (pwd != NULL)
173         {
174                 DEBUG(10, ("found by name: %s\n", nt_name));
175         }
176
177         endsmbpwent(fp);
178         return pwd;
179 }
180
181 /************************************************************************
182  Utility function to search sam passwd by rid.  use this if your database
183  does not have search facilities.
184
185  search capability by both rid and uid are needed as the rid <-> uid
186  mapping may be non-monotonic.  
187
188 *************************************************************************/
189
190 struct sam_passwd *iterate_getsam21pwrid(uint32 rid)
191 {
192         struct sam_passwd *pwd = NULL;
193         void *fp = NULL;
194
195         DEBUG(10, ("search by rid: %x\n", rid));
196
197         /* Open the smb password file - not for update. */
198         fp = startsmbpwent(False);
199
200         if (fp == NULL)
201         {
202                 DEBUG(0, ("unable to open sam password database.\n"));
203                 return NULL;
204         }
205
206         while ((pwd = getsam21pwent(fp)) != NULL && pwd->user_rid != rid)
207         {
208                 DEBUG(10, ("iterate: %s 0x%x\n", pwd->nt_name, pwd->user_rid));
209         }
210
211         if (pwd != NULL)
212         {
213                 DEBUG(10, ("found by user_rid: %x\n", rid));
214         }
215
216         endsmbpwent(fp);
217         return pwd;
218 }
219
220 /************************************************************************
221  Utility function to search sam passwd by uid.  use this if your database
222  does not have search facilities.
223
224  search capability by both rid and uid are needed as the rid <-> uid
225  mapping may be non-monotonic.  
226
227 *************************************************************************/
228
229 struct sam_passwd *iterate_getsam21pwuid(uid_t uid)
230 {
231         struct sam_passwd *pwd = NULL;
232         void *fp = NULL;
233
234         DEBUG(10, ("search by uid: %x\n", (int)uid));
235
236         /* Open the smb password file - not for update. */
237         fp = startsmbpwent(False);
238
239         if (fp == NULL)
240         {
241                 DEBUG(0, ("unable to open sam password database.\n"));
242                 return NULL;
243         }
244
245         while ((pwd = getsam21pwent(fp)) != NULL && pwd->unix_uid != uid)
246         {
247         }
248
249         if (pwd != NULL)
250         {
251                 DEBUG(10, ("found by unix_uid: %x\n", (int)uid));
252         }
253
254         endsmbpwent(fp);
255         return pwd;
256 }
257
258 /*************************************************************************
259  Routine to return a display info structure, by rid
260  *************************************************************************/
261 struct sam_disp_info *getsamdisprid(uint32 rid)
262 {
263         return pwdb_ops->getsamdisprid(rid);
264 }
265
266 /************************************************************************
267  Routine to search sam passwd by name.
268 *************************************************************************/
269
270 struct sam_passwd *getsam21pwntnam(const char *name)
271 {
272         return pwdb_sam_map_names(pwdb_ops->getsam21pwntnam(name));
273 }
274
275 /************************************************************************
276  Routine to search sam passwd by rid.  
277 *************************************************************************/
278
279 struct sam_passwd *getsam21pwrid(uint32 rid)
280 {
281         return pwdb_sam_map_names(pwdb_ops->getsam21pwrid(rid));
282 }
283
284
285 /**********************************************************
286  **********************************************************
287
288  utility routines which are likely to be useful to all password
289  databases
290
291  **********************************************************
292  **********************************************************/
293
294 /*************************************************************
295  initialises a struct sam_disp_info.
296  **************************************************************/
297
298 static void pwdb_init_dispinfo(struct sam_disp_info *user)
299 {
300         if (user == NULL) return;
301         bzero(user, sizeof(*user));
302         user->user_rid = 0xffffffff;
303 }
304
305 /*************************************************************
306  initialises a struct sam_passwd.
307  **************************************************************/
308 void pwdb_init_sam(struct sam_passwd *user)
309 {
310         if (user == NULL) return;
311         bzero(user, sizeof(*user));
312
313         init_nt_time(&user->logon_time);
314         init_nt_time(&user->logoff_time);
315         init_nt_time(&user->kickoff_time);
316         init_nt_time(&user->pass_last_set_time);
317         init_nt_time(&user->pass_can_change_time);
318         init_nt_time(&user->pass_must_change_time);
319
320         user->unix_uid = (uid_t)-1;
321         user->unix_gid = (gid_t)-1;
322         user->user_rid  = 0xffffffff;
323         user->group_rid = 0xffffffff;
324 }
325
326 /*************************************************************************
327  Routine to return the next entry in the sam passwd list.
328  *************************************************************************/
329
330 struct sam_disp_info *pwdb_sam_to_dispinfo(struct sam_passwd *user)
331 {
332         static struct sam_disp_info disp_info;
333
334         if (user == NULL) return NULL;
335
336         pwdb_init_dispinfo(&disp_info);
337
338         disp_info.nt_name   = user->nt_name;
339         disp_info.full_name = user->full_name;
340         disp_info.user_rid  = user->user_rid;
341
342         return &disp_info;
343 }
344
345 static void select_name(fstring string, char **name, const UNISTR2 *from)
346 {
347         if (from->buffer != 0)
348         {
349                 unistr2_to_ascii(string, from, sizeof(string));
350                 *name = string;
351         }
352 }
353
354 /*************************************************************
355  copies a sam passwd.
356  **************************************************************/
357 void copy_id23_to_sam_passwd(struct sam_passwd *to, const SAM_USER_INFO_23 *from)
358 {
359         static fstring nt_name;
360         static fstring full_name;
361         static fstring home_dir;
362         static fstring dir_drive;
363         static fstring logon_script;
364         static fstring profile_path;
365         static fstring acct_desc;
366         static fstring workstations;
367         static fstring unknown_str;
368         static fstring munged_dial;
369
370         if (from == NULL || to == NULL) return;
371
372         memcpy(to, from, sizeof(*from));
373
374         select_name(nt_name     , &to->nt_name     , &from->uni_user_name   );
375         select_name(full_name   , &to->full_name   , &from->uni_full_name   );
376         select_name(home_dir    , &to->home_dir    , &from->uni_home_dir    );
377         select_name(dir_drive   , &to->dir_drive   , &from->uni_dir_drive   );
378         select_name(logon_script, &to->logon_script, &from->uni_logon_script);
379         select_name(profile_path, &to->profile_path, &from->uni_profile_path);
380         select_name(acct_desc   , &to->acct_desc   , &from->uni_acct_desc   );
381         select_name(workstations, &to->workstations, &from->uni_workstations);
382         select_name(unknown_str , &to->unknown_str , &from->uni_unknown_str );
383         select_name(munged_dial , &to->munged_dial , &from->uni_munged_dial );
384 }
385
386
387 /*************************************************************
388  copies a sam passwd.
389  **************************************************************/
390 void copy_sam_passwd(struct sam_passwd *to, const struct sam_passwd *from)
391 {
392         static fstring nt_name;
393         static fstring unix_name;
394         static fstring full_name;
395         static fstring home_dir;
396         static fstring dir_drive;
397         static fstring logon_script;
398         static fstring profile_path;
399         static fstring acct_desc;
400         static fstring workstations;
401         static fstring unknown_str;
402         static fstring munged_dial;
403
404         if (from == NULL || to == NULL) return;
405
406         memcpy(to, from, sizeof(*from));
407
408         if (from->nt_name != NULL)
409         {
410                 fstrcpy(nt_name  , from->nt_name);
411                 to->nt_name = nt_name;
412         }
413         else if (to->nt_name != NULL)
414         {
415                 fstrcpy(nt_name  , to->nt_name);
416                 to->nt_name = nt_name;
417         }
418
419         if (from->unix_name != NULL)
420         {
421                 fstrcpy(unix_name, from->unix_name);
422                 to->unix_name = unix_name;
423         }
424         else if (to->unix_name != NULL)
425         {
426                 fstrcpy(unix_name, to->unix_name);
427                 to->unix_name = unix_name;
428         }
429
430         if (from->full_name != NULL)
431         {
432                 fstrcpy(full_name, from->full_name);
433                 to->full_name = full_name;
434         }
435         else if (to->full_name != NULL)
436         {
437                 fstrcpy(full_name, to->full_name);
438                 to->full_name = full_name;
439         }
440
441         if (from->home_dir != NULL)
442         {
443                 fstrcpy(home_dir  , from->home_dir);
444                 to->home_dir = home_dir;
445         }
446         else if (to->home_dir != NULL)
447         {
448                 fstrcpy(home_dir  , to->home_dir);
449                 to->home_dir = home_dir;
450         }
451
452         if (from->dir_drive != NULL)
453         {
454                 fstrcpy(dir_drive  , from->dir_drive);
455                 to->dir_drive = dir_drive;
456         }
457         else if (to->dir_drive != NULL)
458         {
459                 fstrcpy(dir_drive  , to->dir_drive);
460                 to->dir_drive = dir_drive;
461         }
462
463         if (from->logon_script != NULL)
464         {
465                 fstrcpy(logon_script  , from->logon_script);
466                 to->logon_script = logon_script;
467         }
468         else if (to->logon_script != NULL)
469         {
470                 fstrcpy(logon_script  , to->logon_script);
471                 to->logon_script = logon_script;
472         }
473
474         if (from->profile_path != NULL)
475         {
476                 fstrcpy(profile_path  , from->profile_path);
477                 to->profile_path = profile_path;
478         }
479         else if (to->profile_path != NULL)
480         {
481                 fstrcpy(profile_path  , to->profile_path);
482                 to->profile_path = profile_path;
483         }
484
485         if (from->acct_desc != NULL)
486         {
487                 fstrcpy(acct_desc  , from->acct_desc);
488                 to->acct_desc = acct_desc;
489         }
490         else if (to->acct_desc != NULL)
491         {
492                 fstrcpy(acct_desc  , to->acct_desc);
493                 to->acct_desc = acct_desc;
494         }
495
496         if (from->workstations != NULL)
497         {
498                 fstrcpy(workstations  , from->workstations);
499                 to->workstations = workstations;
500         }
501         else if (to->workstations != NULL)
502         {
503                 fstrcpy(workstations  , to->workstations);
504                 to->workstations = workstations;
505         }
506
507         if (from->unknown_str != NULL)
508         {
509                 fstrcpy(unknown_str  , from->unknown_str);
510                 to->unknown_str = unknown_str;
511         }
512         else if (to->unknown_str != NULL)
513         {
514                 fstrcpy(unknown_str  , to->unknown_str);
515                 to->unknown_str = unknown_str;
516         }
517
518         if (from->munged_dial != NULL)
519         {
520                 fstrcpy(munged_dial  , from->munged_dial);
521                 to->munged_dial = munged_dial;
522         }
523         else if (to->munged_dial != NULL)
524         {
525                 fstrcpy(munged_dial  , to->munged_dial);
526                 to->munged_dial = munged_dial;
527         }
528 }
529
530
531 /*************************************************************
532  converts a sam_passwd structure to a smb_passwd structure.
533  **************************************************************/
534
535 struct smb_passwd *pwdb_sam_to_smb(struct sam_passwd *user)
536 {
537         static struct smb_passwd pw_buf;
538         static fstring nt_name;
539         static fstring unix_name;
540
541         if (user == NULL) return NULL;
542
543         pwdb_init_smb(&pw_buf);
544
545         if (user->nt_name != NULL)
546         {
547                 fstrcpy(nt_name  , user->nt_name);
548                 pw_buf.nt_name = nt_name;
549         }
550         if (user->unix_name != NULL)
551         {
552                 fstrcpy(unix_name, user->unix_name);
553                 pw_buf.unix_name = unix_name;
554         }
555         pw_buf.unix_uid           = user->unix_uid;
556         pw_buf.user_rid           = user->user_rid;
557         pw_buf.smb_passwd         = user->smb_passwd;
558         pw_buf.smb_nt_passwd      = user->smb_nt_passwd;
559         pw_buf.acct_ctrl          = user->acct_ctrl;
560         pw_buf.pass_last_set_time = nt_time_to_unix(&user->pass_last_set_time);
561
562         return &pw_buf;
563 }
564
565
566 /*************************************************************
567  converts a smb_passwd structure to a sam_passwd structure.
568  **************************************************************/
569
570 struct sam_passwd *pwdb_smb_to_sam(struct smb_passwd *user)
571 {
572         static struct sam_passwd pw_buf;
573         static fstring nt_name;
574         static fstring unix_name;
575
576         if (user == NULL) return NULL;
577
578         pwdb_init_sam(&pw_buf);
579
580         if (user->nt_name != NULL)
581         {
582                 fstrcpy(nt_name  , user->nt_name);
583                 pw_buf.nt_name = nt_name;
584         }
585         if (user->unix_name != NULL)
586         {
587                 fstrcpy(unix_name, user->unix_name);
588                 pw_buf.unix_name = unix_name;
589         }
590         pw_buf.unix_uid           = user->unix_uid;
591         pw_buf.user_rid           = user->user_rid;
592         pw_buf.smb_passwd         = user->smb_passwd;
593         pw_buf.smb_nt_passwd      = user->smb_nt_passwd;
594         pw_buf.acct_ctrl          = user->acct_ctrl;
595
596         if ( user->pass_last_set_time != (time_t)-1 )
597         {
598                 unix_to_nt_time(&pw_buf.pass_last_set_time, user->pass_last_set_time);
599                 unix_to_nt_time(&pw_buf.pass_can_change_time, user->pass_last_set_time);
600         }
601
602         return &pw_buf;
603 }
604
605 static BOOL trust_account_warning_done = False;
606
607 /*************************************************************
608  fills in missing details.  one set of details _must_ exist.
609  **************************************************************/
610 struct sam_passwd *pwdb_sam_map_names(struct sam_passwd *sam)
611 {
612         DOM_NAME_MAP gmep;
613         BOOL found = False;
614         DOM_SID sid;
615         static fstring unix_name;
616         static fstring nt_name;
617
618         DEBUG(10,("pwdb_sam_map_names\n"));
619
620         /*
621          * name details
622          */
623
624         if (sam == NULL)
625         {
626                 return NULL;
627         }
628
629         if (!found && sam->unix_name != NULL)
630         {
631                 found = lookupsmbpwnam(sam->unix_name, &gmep);
632         }
633         if (!found && sam->unix_uid  != (uid_t)-1)
634         {
635                 found = lookupsmbpwuid(sam->unix_uid , &gmep);
636         }
637         if (!found && sam->user_rid != 0xffffffff)
638         {
639                 sid_copy(&sid, &global_sam_sid);
640                 sid_append_rid(&sid, sam->user_rid);
641                 found = lookupsmbpwsid  (&sid        , &gmep);
642         }
643         if (!found && sam->nt_name  != NULL)
644         {
645                 found = lookupsmbpwntnam(sam->nt_name, &gmep);
646         }
647
648         if (!found)
649         {
650                 return NULL;
651         }
652
653         if (!sid_front_equal(&global_sam_sid, &gmep.sid))
654         {
655                 return NULL;
656         }
657
658         fstrcpy(unix_name, gmep.unix_name);
659         fstrcpy(nt_name  , gmep.nt_name  );
660         if (sam->unix_name == NULL      ) sam->unix_name = unix_name;
661         if (sam->nt_name   == NULL      ) sam->nt_name   = nt_name  ;
662         if (sam->unix_uid  == (uid_t)-1 ) sam->unix_uid  = (uid_t)gmep.unix_id;
663         if (sam->user_rid  == 0xffffffff) sid_split_rid(&gmep.sid, &sam->user_rid);
664
665         DEBUG(10,("pwdb_sam_map_name: found unix user %s nt %s uid %d rid 0x%x\n",
666                    sam->unix_name, sam->nt_name, sam->unix_uid, sam->user_rid));
667
668         /*
669          * group details
670          */
671
672         found = False;
673
674         if (sam->unix_gid != (gid_t)-1 && sam->group_rid != 0xffffffff)
675         {
676                 return sam;
677         }
678
679         if (sam->unix_gid == (gid_t)-1 && sam->group_rid == 0xffffffff)
680         {
681                 struct passwd *pass = hashed_getpwnam(unix_name);
682                 if (pass != NULL)
683                 {
684                         sam->unix_gid = pass->pw_gid;
685                 }
686                 else
687                 {
688                         DEBUG(0,("pwdb_sam_map_names: no unix password entry for %s\n",
689                                   unix_name));
690                 }
691         }
692
693         if (!found && sam->unix_gid  != (gid_t)-1)
694         {
695                 found = lookupsmbgrpgid(sam->unix_gid , &gmep);
696         }
697         if (!found && sam->group_rid != 0xffffffff)
698         {
699                 sid_copy(&sid, &global_sam_sid);
700                 sid_append_rid(&sid, sam->group_rid);
701                 found = lookupsmbgrpsid(&sid        , &gmep);
702         }
703
704         if (!found)
705         {
706                 if (IS_BITS_SET_SOME(sam->acct_ctrl, ACB_WSTRUST|ACB_DOMTRUST|ACB_SVRTRUST))
707                 {
708                         if (!trust_account_warning_done)
709                         {
710                                 trust_account_warning_done = True;
711                                 DEBUG(0, ("\
712 pwdb_sam_map_names: your unix password database appears to have difficulties\n\
713 resolving trust account %s, probably because it ends in a '$'.\n\
714 you will get this warning only once (for all trust accounts)\n", unix_name));
715                         }
716                         /*
717                          * oh, dear.
718                          */
719                         if (sam->unix_gid != (gid_t)-1)
720                         {
721                                 sam->unix_gid = (gid_t)-1;
722                         }
723                         sam->group_rid = DOMAIN_GROUP_RID_USERS;
724
725                         return sam;
726                 }
727                 else
728                 {
729                         DEBUG(0, ("pwdb_sam_map_names: could not find Primary Group for %s\n",
730                                    unix_name));
731                         return NULL;
732                 }
733         }
734
735         if (!sid_front_equal(&global_sam_sid, &gmep.sid))
736         {
737                 fstring sid_str;
738                 sid_to_string(sid_str, &gmep.sid);
739                 DEBUG(0,("UNIX User %s Primary Group is in the wrong domain! %s\n",
740                           sam->unix_name, sid_str));
741                 return NULL;
742         }
743
744         if (sam->unix_gid  == (gid_t)-1 ) sam->unix_gid  = (gid_t)gmep.unix_id;
745         if (sam->group_rid == 0xffffffff) sid_split_rid(&gmep.sid, &sam->group_rid);
746
747         DEBUG(10,("pwdb_sam_map_name: found gid %d and group rid 0x%x for unix user %s\n",
748                    sam->unix_gid, sam->group_rid, sam->unix_name));
749
750         return sam;
751 }