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