sync'ing up for 3.0alpha20 release
[amitay/samba.git] / source3 / passdb / pdb_nisplus.c
1
2 /*
3  * NIS+ Passdb Backend
4  * Copyright (C) Andrew Tridgell 1992-1998 Modified by Jeremy Allison 1995.
5  * Copyright (C) Benny Holmgren 1998 <bigfoot@astrakan.hgs.se> 
6  * Copyright (C) Luke Kenneth Casson Leighton 1996-1998.
7  * Copyright (C) Toomas Soome <tsoome@ut.ee> 2001
8  * Copyright (C) Jelmer Vernooij 2002
9  * 
10  * This program is free software; you can redistribute it and/or modify it under
11  * the terms of the GNU General Public License as published by the Free
12  * Software Foundation; either version 2 of the License, or (at your option)
13  * any later version.
14  * 
15  * This program is distributed in the hope that it will be useful, but WITHOUT
16  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
17  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
18  * more details.
19  * 
20  * You should have received a copy of the GNU General Public License along with
21  * this program; if not, write to the Free Software Foundation, Inc., 675
22  * Mass Ave, Cambridge, MA 02139, USA.
23  */
24
25 #include "includes.h"
26
27 #ifdef WITH_NISPLUS_SAM
28
29 #ifdef BROKEN_NISPLUS_INCLUDE_FILES
30
31 /*
32  * The following lines are needed due to buggy include files
33  * in Solaris 2.6 which define GROUP in both /usr/include/sys/acl.h and
34  * also in /usr/include/rpcsvc/nis.h. The definitions conflict. JRA.
35  * Also GROUP_OBJ is defined as 0x4 in /usr/include/sys/acl.h and as
36  * an enum in /usr/include/rpcsvc/nis.h.
37  */
38
39
40 #if defined(GROUP)
41 #undef GROUP
42 #endif
43
44 #if defined(GROUP_OBJ)
45 #undef GROUP_OBJ
46 #endif
47
48 #endif
49
50 #include <rpcsvc/nis.h>
51
52 /***************************************************************
53
54  the fields for the NIS+ table, generated from mknissmbpwtbl.sh, are:
55
56                 name=S,nogw=r 
57                 uid=S,nogw=r 
58                 user_rid=S,nogw=r
59                 smb_grpid=,nw+r
60                 group_rid=,nw+r
61                 acb=,nw+r
62
63                 lmpwd=C,nw=,g=r,o=rm 
64                 ntpwd=C,nw=,g=r,o=rm 
65
66                 logon_t=,nw+r 
67                 logoff_t=,nw+r 
68                 kick_t=,nw+r 
69                 pwdlset_t=,nw+r 
70                 pwdlchg_t=,nw+r 
71                 pwdmchg_t=,nw+r 
72                                 
73                 full_name=,nw+r 
74                 home_dir=,nw+r 
75                 dir_drive=,nw+r 
76                 logon_script=,nw+r 
77                 profile_path=,nw+r 
78                 acct_desc=,nw+r 
79                 workstations=,nw+r 
80                                    
81                 hours=,nw+r 
82
83 ****************************************************************/
84
85 #define NPF_NAME          0
86 #define NPF_UID           1
87 #define NPF_USER_RID      2
88 #define NPF_SMB_GRPID     3
89 #define NPF_GROUP_RID     4
90 #define NPF_ACB           5
91 #define NPF_LMPWD         6
92 #define NPF_NTPWD         7
93 #define NPF_LOGON_T       8
94 #define NPF_LOGOFF_T      9
95 #define NPF_KICK_T        10
96 #define NPF_PWDLSET_T     11
97 #define NPF_PWDCCHG_T     12
98 #define NPF_PWDMCHG_T     13
99 #define NPF_FULL_NAME     14
100 #define NPF_HOME_DIR      15
101 #define NPF_DIR_DRIVE     16
102 #define NPF_LOGON_SCRIPT  17
103 #define NPF_PROFILE_PATH  18
104 #define NPF_ACCT_DESC     19
105 #define NPF_WORKSTATIONS  20
106 #define NPF_HOURS         21
107
108 struct nisplus_private_info {
109         nis_result *result;
110         int enum_entry;
111         char *location;
112 };
113
114 static char *make_nisname_from_user_rid (uint32 rid, char *pfile);
115 static char *make_nisname_from_name (const char *user_name, char *pfile);
116 static void get_single_attribute (const nis_object * new_obj, int col,
117                                   char *val, int len);;
118 static BOOL make_sam_from_nisp_object (SAM_ACCOUNT * pw_buf,
119                                        const nis_object * obj);
120 static BOOL make_sam_from_nisresult (SAM_ACCOUNT * pw_buf,
121                                      const nis_result * result);;
122 static void set_single_attribute (nis_object * new_obj, int col,
123                                   const char *val, int len, int flags);
124 static BOOL init_nisp_from_sam (nis_object * obj, const SAM_ACCOUNT * sampass,
125                                 nis_object * old);
126 static nis_result *nisp_get_nis_list (const char *nisname,
127                                       unsigned int flags);
128
129 /***************************************************************
130  Start enumeration of the passwd list.
131 ****************************************************************/
132
133 static BOOL nisplussam_setsampwent (struct pdb_methods *methods, BOOL update)
134 {
135         struct nisplus_private_info *private =
136                 (struct nisplus_private_info *) methods->private_data;
137
138         char *sp;
139         pstring pfiletmp;
140
141         if ((sp = strrchr (private->location, '/')))
142                 safe_strcpy (pfiletmp, sp + 1, sizeof (pfiletmp) - 1);
143         else
144                 safe_strcpy (pfiletmp, p, sizeof (pfiletmp) - 1);
145         safe_strcat (pfiletmp, ".org_dir",
146                      sizeof (pfiletmp) - strlen (pfiletmp) - 1);
147
148         pdb_endsampwent ();     /* just in case */
149         global_nisp_ent->result = nisp_get_nis_list (pfiletmp, 0);
150         global_nisp_ent->enum_entry = 0;
151         return global_nisp_ent->result != NULL ? True : False;
152 }
153
154 /***************************************************************
155  End enumeration of the passwd list.
156 ****************************************************************/
157
158 static void nisplussam_endsampwent (struct pdb_methods *methods)
159 {
160         struct nisplus_private_info *global_nisp_ent =
161                 (struct nisplus_private_info *) methods->private_data;
162         if (global_nisp_ent->result)
163                 nis_freeresult (global_nisp_ent->result);
164         global_nisp_ent->result = NULL;
165         global_nisp_ent->enum_entry = 0;
166 }
167
168 /*****************************************************************
169  Get one SAM_ACCOUNT from the list (next in line)
170 *****************************************************************/
171
172 static BOOL nisplussam_getsampwent (struct pdb_methods *methods,
173                                     SAM_ACCOUNT * user)
174 {
175
176         struct nisplus_private_info *global_nisp_ent =
177                 (struct nisplus_private_info *) methods->private_data;
178         int enum_entry = (int) (global_nisp_ent->enum_entry);
179         nis_result *result = global_nisp_ent->result;
180
181         if (user == NULL) {
182                 DEBUG (0, ("SAM_ACCOUNT is NULL.\n"));
183                 return False;
184         }
185
186         if (result == NULL ||
187             enum_entry < 0 || enum_entry >= (NIS_RES_NUMOBJ (result) - 1)) {
188                 return False;
189         }
190
191         if (!make_sam_from_nisp_object
192             (user, &NIS_RES_OBJECT (result)[enum_entry])) {
193                 DEBUG (0, ("Bad SAM_ACCOUNT entry returned from NIS+!\n"));
194                 return False;
195         }
196         (int) (global_nisp_ent->enum_entry)++;
197         return True;
198         DEBUG (10, ("nisplussam_getsampwent called\n"));
199         return False;
200 }
201
202 /******************************************************************
203  Lookup a name in the SAM database
204 ******************************************************************/
205
206 static BOOL nisplussam_getsampwnam (struct pdb_methods *methods,
207                                     SAM_ACCOUNT * user, const char *sname)
208 {
209         /* Static buffers we will return. */
210         nis_result *result = NULL;
211         pstring nisname;
212         BOOL ret;
213         struct nisplus_private_info *private =
214                 (struct nisplus_private_info *) methods->private_data;
215
216         if (!private->location || !(*private->location)) {
217                 DEBUG (0, ("No SMB password file set\n"));
218                 return False;
219         }
220         if (strrchr (private->location, '/'))
221                 private->location = strrchr (private->location, '/') + 1;
222
223         slprintf (nisname, sizeof (nisname) - 1, "[name=%s],%s.org_dir",
224                   sname, private->location);
225         DEBUG (10, ("search by nisname: %s\n", nisname));
226
227         /* Search the table. */
228
229         if (!(result = nisp_get_nis_list (nisname, 0))) {
230                 return False;
231         }
232
233         ret = make_sam_from_nisresult (user, result);
234         nis_freeresult (result);
235
236         return ret;
237
238         DEBUG (10, ("nisplussam_getsampwnam called\n"));
239         return False;
240 }
241
242 /***************************************************************************
243  Search by sid
244  **************************************************************************/
245
246 static BOOL nisplussam_getsampwrid (struct pdb_methods *methods,
247                                     SAM_ACCOUNT * user, uint32 rid)
248 {
249         nis_result *result;
250         char *nisname;
251         BOOL ret;
252         char *sp;
253         pstring pfiletmp;
254         struct nisplus_private_info *private =
255                 (struct nisplus_private_info *) methods->private_data;
256
257         if (!private->location || !(*private->location)) {
258                 DEBUG (0, ("no SMB password file set\n"));
259                 return False;
260         }
261
262         if ((sp = strrchr (private->location, '/')))
263                 safe_strcpy (pfiletmp, sp + 1, sizeof (pfiletmp) - 1);
264         else
265                 safe_strcpy (pfiletmp, private->location, sizeof (pfiletmp) - 1);
266         safe_strcat (pfiletmp, ".org_dir",
267                      sizeof (pfiletmp) - strlen (pfiletmp) - 1);
268
269         nisname = make_nisname_from_user_rid (rid, pfiletmp);
270
271         DEBUG (10, ("search by rid: %s\n", nisname));
272
273         /* Search the table. */
274
275         if (!(result = nisp_get_nis_list (nisname, 0))) {
276                 return False;
277         }
278
279         ret = make_sam_from_nisresult (user, result);
280         nis_freeresult (result);
281
282         return ret;
283 }
284
285 static BOOL nisplussam_getsampwsid (struct pdb_methods *methods,
286                                     SAM_ACCOUNT * user, const DOM_SID * sid)
287 {
288         uint32 rid;
289
290         if (!sid_peek_check_rid (get_global_sam_sid (), sid, &rid))
291                 return False;
292         return nisplussam_getsampwrid (methods, user, rid);
293 }
294
295
296
297 /***************************************************************************
298  Delete a SAM_ACCOUNT
299 ****************************************************************************/
300
301 static BOOL nisplussam_delete_sam_account (struct pdb_methods *methods,
302                                            SAM_ACCOUNT * user)
303 {
304         const char *sname;
305         pstring nisname;
306         nis_result *result, *delresult;
307         nis_object *obj;
308         struct nisplus_private_info *private =
309                 (struct nisplus_private_info *) methods->private_data;
310
311         if (!user) {
312                 DEBUG (0, ("no SAM_ACCOUNT specified!\n"));
313                 return False;
314         }
315
316         sname = pdb_get_username (user);
317
318         if (!private->location || !(*private->location)) {
319                 DEBUG (0, ("no SMB password file set\n"));
320                 return False;
321         }
322
323         if (strrchr (private->location, '/'))
324                 private->location = strrchr (private->location, '/') + 1;
325
326         slprintf (nisname, sizeof (nisname) - 1, "[name=%s],%s.org_dir",
327                   sname, private->location);
328
329         /* Search the table. */
330
331         if (!(result = nisp_get_nis_list (nisname,
332                                           MASTER_ONLY | FOLLOW_LINKS |
333                                           FOLLOW_PATH | EXPAND_NAME |
334                                           HARD_LOOKUP))) {
335                 return False;
336         }
337
338         if (result->status != NIS_SUCCESS || NIS_RES_NUMOBJ (result) <= 0) {
339                 /* User not found. */
340                 DEBUG (0, ("user not found in NIS+\n"));
341                 nis_freeresult (result);
342                 return False;
343         }
344
345         obj = NIS_RES_OBJECT (result);
346         slprintf (nisname, sizeof (nisname) - 1, "[name=%s],%s.%s", sname,
347                   obj->zo_name, obj->zo_domain);
348
349         DEBUG (10, ("removing name: %s\n", nisname));
350         delresult = nis_remove_entry (nisname, obj,
351                                       MASTER_ONLY | REM_MULTIPLE | ALL_RESULTS
352                                       | FOLLOW_PATH | EXPAND_NAME |
353                                       HARD_LOOKUP);
354
355         nis_freeresult (result);
356
357         if (delresult->status != NIS_SUCCESS) {
358                 DEBUG (0, ("NIS+ table update failed: %s %s\n",
359                            nisname, nis_sperrno (delresult->status)));
360                 nis_freeresult (delresult);
361                 return False;
362         }
363         nis_freeresult (delresult);
364         return True;
365         DEBUG (10, ("nisplussam_delete_sam_account called\n"));
366         return False;
367 }
368
369 /***************************************************************************
370  Modifies an existing SAM_ACCOUNT
371 ****************************************************************************/
372
373 static BOOL nisplussam_update_sam_account (struct pdb_methods *methods,
374                                            SAM_ACCOUNT * newpwd)
375 {
376         nis_result *result, *addresult;
377         nis_object *obj;
378         nis_object new_obj;
379         entry_col *ecol;
380         int ta_maxcol;
381         struct nisplus_private_info *private =
382                 (struct nisplus_private_info *) methods->private_data;
383         pstring nisname;
384
385         if (!private->location || !(*private->location)) {
386                 DEBUG (0, ("no SMB password file set\n"));
387                 return False;
388         }
389         if (strrchr (private->location, '/'))
390                 private->location = strrchr (private->location, '/') + 1;
391
392         slprintf (nisname, sizeof (nisname) - 1, "[name=%s],%s.org_dir",
393                   pdb_get_username (newpwd), private->location);
394
395         DEBUG (10, ("search by name: %s\n", nisname));
396
397         /* Search the table. */
398
399         if (!
400             (result =
401              nisp_get_nis_list (nisname,
402                                 MASTER_ONLY | FOLLOW_LINKS | FOLLOW_PATH |
403                                 EXPAND_NAME | HARD_LOOKUP))) {
404                 return False;
405         }
406
407         if (result->status != NIS_SUCCESS || NIS_RES_NUMOBJ (result) <= 0) {
408                 /* User not found. */
409                 DEBUG (0, ("user not found in NIS+\n"));
410                 nis_freeresult (result);
411                 return False;
412         }
413
414         obj = NIS_RES_OBJECT (result);
415         DEBUG (6, ("entry found in %s\n", obj->zo_domain));
416
417         /* we must create new stub object with EN_MODIFIED flag.
418            this is because obj from result is going to be freed and
419            we do not want to break it or cause memory leaks or corruption.
420          */
421
422         memmove ((char *) &new_obj, obj, sizeof (new_obj));
423         ta_maxcol = obj->TA_data.ta_maxcol;
424
425         if (!(ecol = (entry_col *) malloc (ta_maxcol * sizeof (entry_col)))) {
426                 DEBUG (0, ("memory allocation failure\n"));
427                 nis_freeresult (result);
428                 return False;
429         }
430
431         memmove ((char *) ecol, obj->EN_data.en_cols.en_cols_val,
432                  ta_maxcol * sizeof (entry_col));
433         new_obj.EN_data.en_cols.en_cols_val = ecol;
434         new_obj.EN_data.en_cols.en_cols_len = ta_maxcol;
435
436         if (init_nisp_from_sam (&new_obj, newpwd, obj) == True) {
437                 slprintf (nisname, sizeof (nisname) - 1, "[name=%s],%s.%s",
438                           pdb_get_username (newpwd), private->location, obj->zo_domain);
439
440                 DEBUG (10, ("NIS+ table update: %s\n", nisname));
441                 addresult =
442                         nis_modify_entry (nisname, &new_obj,
443                                           MOD_SAMEOBJ | FOLLOW_PATH |
444                                           EXPAND_NAME | HARD_LOOKUP);
445
446                 if (addresult->status != NIS_SUCCESS) {
447                         DEBUG (0, ("NIS+ table update failed: %s %s\n",
448                                    nisname, nis_sperrno (addresult->status)));
449                         nis_freeresult (addresult);
450                         nis_freeresult (result);
451                         free (ecol);
452                         return False;
453                 }
454
455                 DEBUG (6, ("password changed\n"));
456                 nis_freeresult (addresult);
457         } else {
458                 DEBUG (6, ("nothing to change!\n"));
459         }
460
461         free (ecol);
462         nis_freeresult (result);
463
464         return True;
465 }
466
467 /***************************************************************************
468  Adds an existing SAM_ACCOUNT
469 ****************************************************************************/
470
471 static BOOL nisplussam_add_sam_account (struct pdb_methods *methods,
472                                         SAM_ACCOUNT * newpwd)
473 {
474         int local_user = 0;
475         char *pfile;
476         pstring pfiletmp;
477         char *nisname;
478         nis_result *result = NULL, *tblresult = NULL;
479         nis_object new_obj;
480         entry_col *ecol;
481         int ta_maxcol;
482
483         /*
484          * 1. find user domain.
485          *   a. try nis search in passwd.org_dir - if found use domain from result.
486          *   b. try getpwnam. this may be needed if user is defined
487          *      in /etc/passwd file (or elsewere) and not in passwd.org_dir.
488          *      if found, use host default domain.
489          *   c. exit with False - no such user.
490          *
491          * 2. add user
492          *   a. find smbpasswd table
493          *      search pfile in user domain if not found, try host default
494          *      domain. 
495          *   b. smbpasswd domain is found, fill data and add entry.
496          *
497          * pfile should contain ONLY table name, org_dir will be concated.
498          * so, at first we will clear path prefix from pfile, and
499          * then we will use pfiletmp as playground to put together full
500          * nisname string.
501          * such approach will make it possible to specify samba private dir
502          * AND still use NIS+ table. as all domain related data is normally
503          * stored in org_dir.DOMAIN, this should be ok do do.
504          */
505
506         pfile = private->location;
507         if (strrchr (pfile, '/'))
508                 pfile = strrchr (pfile, '/') + 1;
509
510         /*
511          * Check if user is already there.
512          */
513         safe_strcpy (pfiletmp, pfile, sizeof (pfiletmp) - 1);
514         safe_strcat (pfiletmp, ".org_dir",
515                      sizeof (pfiletmp) - strlen (pfiletmp) - 1);
516
517         if (pdb_get_username (newpwd) != NULL) {
518                 nisname = make_nisname_from_name (pdb_get_username (newpwd),
519                                                   pfiletmp);
520         } else {
521                 return False;
522         }
523
524         if (!
525             (result =
526              nisp_get_nis_list (nisname,
527                                 MASTER_ONLY | FOLLOW_LINKS | FOLLOW_PATH |
528                                 EXPAND_NAME | HARD_LOOKUP))) {
529                 return False;
530         }
531         if (result->status != NIS_SUCCESS && result->status != NIS_NOTFOUND) {
532                 DEBUG (3, ("nis_list failure: %s: %s\n",
533                            nisname, nis_sperrno (result->status)));
534                 nis_freeresult (result);
535                 return False;
536         }
537
538         if (result->status == NIS_SUCCESS && NIS_RES_NUMOBJ (result) > 0) {
539                 DEBUG (3, ("User already exists in NIS+ password db: %s\n",
540                            pfile));
541                 nis_freeresult (result);
542                 return False;
543         }
544
545         nis_freeresult (result);        /* no such user, free results */
546
547         /*
548          * check for user in unix password database. we need this to get
549          * domain, where smbpasswd entry should be stored.
550          */
551
552         nisname = make_nisname_from_name (pdb_get_username (newpwd),
553                                           "passwd.org_dir");
554
555         result = nisp_get_nis_list (nisname,
556                                     MASTER_ONLY | FOLLOW_LINKS | FOLLOW_PATH |
557                                     EXPAND_NAME | HARD_LOOKUP);
558
559         if (result->status != NIS_SUCCESS || NIS_RES_NUMOBJ (result) <= 0) {
560                 struct passwd *passwd;
561
562                 DEBUG (3, ("nis_list failure: %s: %s\n",
563                            nisname, nis_sperrno (result->status)));
564                 nis_freeresult (result);
565
566                 if (!(passwd = getpwnam_alloc (pdb_get_username (newpwd)))) {
567                         /* no such user in system! */
568                         return False;
569                 }
570                 passwd_free (&passwd);
571
572                 /* 
573                  * user is defined, but not in passwd.org_dir.
574                  */
575                 local_user = 1;
576         } else {
577                 safe_strcpy (pfiletmp, pfile, sizeof (pfiletmp) - 1);
578                 safe_strcat (pfiletmp, ".",
579                              sizeof (pfiletmp) - strlen (pfiletmp) - 1);
580                 safe_strcat (pfiletmp, NIS_RES_OBJECT (result)->zo_domain,
581                              sizeof (pfiletmp) - strlen (pfiletmp) - 1);
582                 nis_freeresult (result);        /* not needed any more */
583
584                 tblresult = nisp_get_nis_list (pfiletmp,
585                                                MASTER_ONLY | FOLLOW_LINKS |
586                                                FOLLOW_PATH | EXPAND_NAME |
587                                                HARD_LOOKUP);
588         }
589
590         if (local_user || tblresult->status != NIS_SUCCESS) {
591                 /*
592                  * no user domain or
593                  * smbpasswd table not found in user domain, fallback to
594                  * default domain.
595                  */
596                 if (!local_user)        /* free previous failed search result */
597                         nis_freeresult (tblresult);
598
599                 safe_strcpy (pfiletmp, pfile, sizeof (pfiletmp) - 1);
600                 safe_strcat (pfiletmp, ".org_dir",
601                              sizeof (pfiletmp) - strlen (pfiletmp) - 1);
602                 tblresult = nis_lookup (pfiletmp, MASTER_ONLY | FOLLOW_LINKS |
603                                         FOLLOW_PATH | EXPAND_NAME |
604                                         HARD_LOOKUP);
605                 if (tblresult->status != NIS_SUCCESS) {
606                         /* still nothing. bail out */
607                         nis_freeresult (tblresult);
608                         DEBUG (3, ("nis_lookup failure: %s\n",
609                                    nis_sperrno (tblresult->status)));
610                         return False;
611                 }
612                 /* we need full name for nis_add_entry() */
613                 safe_strcpy (pfiletmp, pfile, sizeof (pfiletmp) - 1);
614                 safe_strcat (pfiletmp, ".",
615                              sizeof (pfiletmp) - strlen (pfiletmp) - 1);
616                 safe_strcat (pfiletmp, NIS_RES_OBJECT (tblresult)->zo_domain,
617                              sizeof (pfiletmp) - strlen (pfiletmp) - 1);
618         }
619
620         memset ((char *) &new_obj, 0, sizeof (new_obj));
621         /* fill entry headers */
622         /* we do not free these. */
623         new_obj.zo_name = NIS_RES_OBJECT (tblresult)->zo_name;
624         new_obj.zo_owner = NIS_RES_OBJECT (tblresult)->zo_owner;
625         new_obj.zo_group = NIS_RES_OBJECT (tblresult)->zo_group;
626         new_obj.zo_domain = NIS_RES_OBJECT (tblresult)->zo_domain;
627         /* uints */
628         new_obj.zo_access = NIS_RES_OBJECT (tblresult)->zo_access;
629         new_obj.zo_ttl = NIS_RES_OBJECT (tblresult)->zo_ttl;
630
631         new_obj.zo_data.zo_type = ENTRY_OBJ;
632         new_obj.EN_data.en_type = NIS_RES_OBJECT (tblresult)->TA_data.ta_type;
633
634         ta_maxcol = NIS_RES_OBJECT (tblresult)->TA_data.ta_maxcol;
635
636         if (!(ecol = (entry_col *) malloc (ta_maxcol * sizeof (entry_col)))) {
637                 DEBUG (0, ("memory allocation failure\n"));
638                 nis_freeresult (tblresult);
639                 return False;
640         }
641
642         memset ((char *) ecol, 0, ta_maxcol * sizeof (entry_col));
643         new_obj.EN_data.en_cols.en_cols_val = ecol;
644         new_obj.EN_data.en_cols.en_cols_len = ta_maxcol;
645
646         init_nisp_from_sam (&new_obj, newpwd, NULL);
647
648         DEBUG (10, ("add NIS+ entry: %s\n", nisname));
649         result = nis_add_entry (pfiletmp, &new_obj, 0);
650
651         free (ecol);            /* free allocated entry space */
652
653         if (result->status != NIS_SUCCESS) {
654                 DEBUG (3, ("NIS+ table update failed: %s,%s\n",
655                            nisname, nis_sperrno (result->status)));
656                 nis_freeresult (tblresult);
657                 nis_freeresult (result);
658                 return False;
659         }
660
661         nis_freeresult (tblresult);
662         nis_freeresult (result);
663
664         return True;
665 }
666
667 /***************************************************************
668  make_nisname_from_user_rid
669  ****************************************************************/
670 static char *make_nisname_from_user_rid (uint32 rid, char *pfile)
671 {
672         static pstring nisname;
673
674         safe_strcpy (nisname, "[user_rid=", sizeof (nisname) - 1);
675         slprintf (nisname, sizeof (nisname) - 1, "%s%d", nisname, rid);
676         safe_strcat (nisname, "],", sizeof (nisname) - strlen (nisname) - 1);
677         safe_strcat (nisname, pfile, sizeof (nisname) - strlen (nisname) - 1);
678
679         return nisname;
680 }
681
682 /***************************************************************
683  make_nisname_from_name
684  ****************************************************************/
685 static char *make_nisname_from_name (const char *user_name, char *pfile)
686 {
687         static pstring nisname;
688
689         safe_strcpy (nisname, "[name=", sizeof (nisname) - 1);
690         safe_strcat (nisname, user_name,
691                      sizeof (nisname) - strlen (nisname) - 1);
692         safe_strcat (nisname, "],", sizeof (nisname) - strlen (nisname) - 1);
693         safe_strcat (nisname, pfile, sizeof (nisname) - strlen (nisname) - 1);
694
695         return nisname;
696 }
697
698 /*************************************************************************
699  gets a NIS+ attribute
700  *************************************************************************/
701 static void get_single_attribute (const nis_object * new_obj, int col,
702                                   char *val, int len)
703 {
704         int entry_len;
705
706         if (new_obj == NULL || val == NULL)
707                 return;
708
709         entry_len = ENTRY_LEN (new_obj, col);
710         if (len > entry_len) {
711                 len = entry_len;
712         }
713
714         safe_strcpy (val, ENTRY_VAL (new_obj, col), len - 1);
715 }
716
717 /************************************************************************
718  makes a struct sam_passwd from a NIS+ object.
719  ************************************************************************/
720 static BOOL make_sam_from_nisp_object (SAM_ACCOUNT * pw_buf,
721                                        const nis_object * obj)
722 {
723         char *ptr;
724         pstring full_name;      /* this must be translated to dos code page */
725         pstring acct_desc;      /* this must be translated to dos code page */
726         pstring home_dir;       /* set default value from smb.conf for user */
727         pstring home_drive;     /* set default value from smb.conf for user */
728         pstring logon_script;   /* set default value from smb.conf for user */
729         pstring profile_path;   /* set default value from smb.conf for user */
730         pstring hours;
731         int hours_len;
732         unsigned char smbpwd[16];
733         unsigned char smbntpwd[16];
734
735
736         /*
737          * time values. note: this code assumes 32bit time_t!
738          */
739
740         /* Don't change these timestamp settings without a good reason.  They are
741            important for NT member server compatibility. */
742
743         pdb_set_logon_time (pw_buf, (time_t) 0, True);
744         ptr = (uchar *) ENTRY_VAL (obj, NPF_LOGON_T);
745         if (ptr && *ptr && (StrnCaseCmp (ptr, "LNT-", 4) == 0)) {
746                 int i;
747
748                 ptr += 4;
749                 for (i = 0; i < 8; i++) {
750                         if (ptr[i] == '\0' || !isxdigit (ptr[i]))
751                                 break;
752                 }
753                 if (i == 8) {
754                         pdb_set_logon_time (pw_buf,
755                                             (time_t) strtol (ptr, NULL, 16),
756                                             True);
757                 }
758         }
759
760         pdb_set_logoff_time (pw_buf, get_time_t_max (), True);
761         ptr = (uchar *) ENTRY_VAL (obj, NPF_LOGOFF_T);
762         if (ptr && *ptr && (StrnCaseCmp (ptr, "LOT-", 4) == 0)) {
763                 int i;
764
765                 ptr += 4;
766                 for (i = 0; i < 8; i++) {
767                         if (ptr[i] == '\0' || !isxdigit (ptr[i]))
768                                 break;
769                 }
770                 if (i == 8) {
771                         pdb_set_logoff_time (pw_buf,
772                                              (time_t) strtol (ptr, NULL, 16),
773                                              True);
774                 }
775         }
776
777         pdb_set_kickoff_time (pw_buf, get_time_t_max (), True);
778         ptr = (uchar *) ENTRY_VAL (obj, NPF_KICK_T);
779         if (ptr && *ptr && (StrnCaseCmp (ptr, "KOT-", 4) == 0)) {
780                 int i;
781
782                 ptr += 4;
783                 for (i = 0; i < 8; i++) {
784                         if (ptr[i] == '\0' || !isxdigit (ptr[i]))
785                                 break;
786                 }
787                 if (i == 8) {
788                         pdb_set_kickoff_time (pw_buf,
789                                               (time_t) strtol (ptr, NULL, 16),
790                                               True);
791                 }
792         }
793
794         pdb_set_pass_last_set_time (pw_buf, (time_t) 0);
795         ptr = (uchar *) ENTRY_VAL (obj, NPF_PWDLSET_T);
796         if (ptr && *ptr && (StrnCaseCmp (ptr, "LCT-", 4) == 0)) {
797                 int i;
798
799                 ptr += 4;
800                 for (i = 0; i < 8; i++) {
801                         if (ptr[i] == '\0' || !isxdigit (ptr[i]))
802                                 break;
803                 }
804                 if (i == 8) {
805                         pdb_set_pass_last_set_time (pw_buf,
806                                                     (time_t) strtol (ptr,
807                                                                      NULL,
808                                                                      16));
809                 }
810         }
811
812         pdb_set_pass_can_change_time (pw_buf, (time_t) 0, True);
813         ptr = (uchar *) ENTRY_VAL (obj, NPF_PWDCCHG_T);
814         if (ptr && *ptr && (StrnCaseCmp (ptr, "CCT-", 4) == 0)) {
815                 int i;
816
817                 ptr += 4;
818                 for (i = 0; i < 8; i++) {
819                         if (ptr[i] == '\0' || !isxdigit (ptr[i]))
820                                 break;
821                 }
822                 if (i == 8) {
823                         pdb_set_pass_can_change_time (pw_buf,
824                                                       (time_t) strtol (ptr,
825                                                                        NULL,
826                                                                        16),
827                                                       True);
828                 }
829         }
830
831         pdb_set_pass_must_change_time (pw_buf, get_time_t_max (), True);        /* Password never expires. */
832         ptr = (uchar *) ENTRY_VAL (obj, NPF_PWDMCHG_T);
833         if (ptr && *ptr && (StrnCaseCmp (ptr, "MCT-", 4) == 0)) {
834                 int i;
835
836                 ptr += 4;
837                 for (i = 0; i < 8; i++) {
838                         if (ptr[i] == '\0' || !isxdigit (ptr[i]))
839                                 break;
840                 }
841                 if (i == 8) {
842                         pdb_set_pass_must_change_time (pw_buf,
843                                                        (time_t) strtol (ptr,
844                                                                         NULL,
845                                                                         16),
846                                                        True);
847                 }
848         }
849
850         /* string values */
851         pdb_set_username (pw_buf, ENTRY_VAL (obj, NPF_NAME));
852         pdb_set_domain (pw_buf, lp_workgroup ());
853         /* pdb_set_nt_username() -- cant set it here... */
854
855         get_single_attribute (obj, NPF_FULL_NAME, full_name,
856                               sizeof (pstring));
857 #if 0
858         unix_to_dos (full_name, True);
859 #endif
860         pdb_set_fullname (pw_buf, full_name);
861
862         pdb_set_acct_ctrl (pw_buf, pdb_decode_acct_ctrl (ENTRY_VAL (obj,
863                                                                     NPF_ACB)));
864
865         get_single_attribute (obj, NPF_ACCT_DESC, acct_desc,
866                               sizeof (pstring));
867 #if 0
868         unix_to_dos (acct_desc, True);
869 #endif
870         pdb_set_acct_desc (pw_buf, acct_desc);
871
872         pdb_set_workstations (pw_buf, ENTRY_VAL (obj, NPF_WORKSTATIONS));
873         pdb_set_munged_dial (pw_buf, NULL);
874
875         pdb_set_uid (pw_buf, atoi (ENTRY_VAL (obj, NPF_UID)));
876         pdb_set_gid (pw_buf, atoi (ENTRY_VAL (obj, NPF_SMB_GRPID)));
877         pdb_set_user_sid_from_rid (pw_buf,
878                                    atoi (ENTRY_VAL (obj, NPF_USER_RID)));
879         pdb_set_group_sid_from_rid (pw_buf,
880                                     atoi (ENTRY_VAL (obj, NPF_GROUP_RID)));
881
882         /* values, must exist for user */
883         if (!(pdb_get_acct_ctrl (pw_buf) & ACB_WSTRUST)) {
884
885                 get_single_attribute (obj, NPF_HOME_DIR, home_dir,
886                                       sizeof (pstring));
887                 if (!(home_dir && *home_dir)) {
888                         pstrcpy (home_dir, lp_logon_home ());
889                         pdb_set_homedir (pw_buf, home_dir, False);
890                 } else
891                         pdb_set_homedir (pw_buf, home_dir, True);
892
893                 get_single_attribute (obj, NPF_DIR_DRIVE, home_drive,
894                                       sizeof (pstring));
895                 if (!(home_drive && *home_drive)) {
896                         pstrcpy (home_drive, lp_logon_drive ());
897                         pdb_set_dir_drive (pw_buf, home_drive, False);
898                 } else
899                         pdb_set_dir_drive (pw_buf, home_drive, True);
900
901                 get_single_attribute (obj, NPF_LOGON_SCRIPT, logon_script,
902                                       sizeof (pstring));
903                 if (!(logon_script && *logon_script)) {
904                         pstrcpy (logon_script, lp_logon_script ());
905                 } else
906                         pdb_set_logon_script (pw_buf, logon_script, True);
907
908                 get_single_attribute (obj, NPF_PROFILE_PATH, profile_path,
909                                       sizeof (pstring));
910                 if (!(profile_path && *profile_path)) {
911                         pstrcpy (profile_path, lp_logon_path ());
912                         pdb_set_profile_path (pw_buf, profile_path, False);
913                 } else
914                         pdb_set_profile_path (pw_buf, profile_path, True);
915
916         } else {
917                 /* lkclXXXX this is OBSERVED behaviour by NT PDCs, enforced here. */
918                 pdb_set_group_sid_from_rid (pw_buf, DOMAIN_GROUP_RID_USERS);
919         }
920
921         /* Check the lanman password column. */
922         ptr = (char *) ENTRY_VAL (obj, NPF_LMPWD);
923         if (!pdb_set_lanman_passwd (pw_buf, NULL))
924                 return False;
925
926         if (!strncasecmp (ptr, "NO PASSWORD", 11)) {
927                 pdb_set_acct_ctrl (pw_buf,
928                                    pdb_get_acct_ctrl (pw_buf) | ACB_PWNOTREQ);
929         } else {
930                 if (strlen (ptr) != 32 || !pdb_gethexpwd (ptr, smbpwd)) {
931                         DEBUG (0, ("malformed LM pwd entry: %s.\n",
932                                    pdb_get_username (pw_buf)));
933                         return False;
934                 }
935                 if (!pdb_set_lanman_passwd (pw_buf, smbpwd))
936                         return False;
937         }
938
939         /* Check the NT password column. */
940         ptr = ENTRY_VAL (obj, NPF_NTPWD);
941         if (!pdb_set_nt_passwd (pw_buf, NULL))
942                 return False;
943
944         if (!(pdb_get_acct_ctrl (pw_buf) & ACB_PWNOTREQ) &&
945             strncasecmp (ptr, "NO PASSWORD", 11)) {
946                 if (strlen (ptr) != 32 || !pdb_gethexpwd (ptr, smbntpwd)) {
947                         DEBUG (0, ("malformed NT pwd entry:\
948  uid = %d.\n", pdb_get_uid (pw_buf)));
949                         return False;
950                 }
951                 if (!pdb_set_nt_passwd (pw_buf, smbntpwd))
952                         return False;
953         }
954
955         pdb_set_unknown_3 (pw_buf, 0xffffff);   /* don't know */
956         pdb_set_logon_divs (pw_buf, 168);       /* hours per week */
957
958         if ((hours_len = ENTRY_LEN (obj, NPF_HOURS)) == 21) {
959                 memcpy (hours, ENTRY_VAL (obj, NPF_HOURS), hours_len);
960         } else {
961                 hours_len = 21; /* 21 times 8 bits = 168 */
962                 /* available at all hours */
963                 memset (hours, 0xff, hours_len);
964         }
965         pdb_set_hours_len (pw_buf, hours_len);
966         pdb_set_hours (pw_buf, hours);
967
968         pdb_set_unknown_5 (pw_buf, 0x00020000); /* don't know */
969         pdb_set_unknown_6 (pw_buf, 0x000004ec); /* don't know */
970
971         return True;
972 }
973
974 /************************************************************************
975  makes a struct sam_passwd from a NIS+ result.
976  ************************************************************************/
977 static BOOL make_sam_from_nisresult (SAM_ACCOUNT * pw_buf,
978                                      const nis_result * result)
979 {
980         if (pw_buf == NULL || result == NULL)
981                 return False;
982
983         if (result->status != NIS_SUCCESS && result->status != NIS_NOTFOUND) {
984                 DEBUG (0, ("NIS+ lookup failure: %s\n",
985                            nis_sperrno (result->status)));
986                 return False;
987         }
988
989         /* User not found. */
990         if (NIS_RES_NUMOBJ (result) <= 0) {
991                 DEBUG (10, ("user not found in NIS+\n"));
992                 return False;
993         }
994
995         if (NIS_RES_NUMOBJ (result) > 1) {
996                 DEBUG (10,
997                        ("WARNING: Multiple entries for user in NIS+ table!\n"));
998         }
999
1000         /* Grab the first hit. */
1001         return make_sam_from_nisp_object (pw_buf,
1002                                           &NIS_RES_OBJECT (result)[0]);
1003 }
1004
1005 /*************************************************************************
1006  sets a NIS+ attribute
1007  *************************************************************************/
1008 static void set_single_attribute (nis_object * new_obj, int col,
1009                                   const char *val, int len, int flags)
1010 {
1011         if (new_obj == NULL)
1012                 return;
1013
1014         ENTRY_VAL (new_obj, col) = val;
1015         ENTRY_LEN (new_obj, col) = len + 1;
1016
1017         if (flags != 0) {
1018                 new_obj->EN_data.en_cols.en_cols_val[col].ec_flags = flags;
1019         }
1020 }
1021
1022 /***************************************************************
1023  copy or modify nis object. this object is used to add or update
1024  nisplus table entry.
1025  ****************************************************************/
1026 static BOOL init_nisp_from_sam (nis_object * obj, const SAM_ACCOUNT * sampass,
1027                                 nis_object * old)
1028 {
1029         /*
1030          * Fill nis_object for entry add or update.
1031          * if we are updateing, we have to find out differences and set
1032          * EN_MODIFIED flag. also set need_to_modify to trigger
1033          * nis_modify_entry() call in pdb_update_sam_account().
1034          *
1035          * TODO:
1036          *   get data from SAM
1037          *   if (modify) get data from nis_object, compare and store if
1038          *               different + set EN_MODIFIED and need_to_modify
1039          *   else
1040          *               store
1041          */
1042         BOOL need_to_modify = False;
1043         const char *name = pdb_get_username (sampass);  /* from SAM */
1044
1045         /* these must be static or allocate and free entry columns! */
1046         static fstring uid;     /* from SAM */
1047         static fstring user_rid;        /* from SAM */
1048         static fstring gid;     /* from SAM */
1049         static fstring group_rid;       /* from SAM */
1050         char *acb;              /* from SAM */
1051         static fstring smb_passwd;      /* from SAM */
1052         static fstring smb_nt_passwd;   /* from SAM */
1053         static fstring logon_t; /* from SAM */
1054         static fstring logoff_t;        /* from SAM */
1055         static fstring kickoff_t;       /* from SAM */
1056         static fstring pwdlset_t;       /* from SAM */
1057         static fstring pwdlchg_t;       /* from SAM */
1058         static fstring pwdmchg_t;       /* from SAM */
1059         static fstring full_name;       /* from SAM */
1060         static fstring acct_desc;       /* from SAM */
1061         static char empty[1];   /* just an empty string */
1062
1063         slprintf (uid, sizeof (uid) - 1, "%u", pdb_get_uid (sampass));
1064         slprintf (user_rid, sizeof (user_rid) - 1, "%u",
1065                   pdb_get_user_rid (sampass) ? pdb_get_user_rid (sampass) :
1066                   fallback_pdb_uid_to_user_rid (pdb_get_uid (sampass)));
1067         slprintf (gid, sizeof (gid) - 1, "%u", pdb_get_gid (sampass));
1068
1069         {
1070                 uint32 rid;
1071                 GROUP_MAP map;
1072
1073                 rid = pdb_get_group_rid (sampass);
1074
1075                 if (rid == 0) {
1076                         if (get_group_map_from_gid
1077                             (pdb_get_gid (sampass), &map,
1078                              MAPPING_WITHOUT_PRIV)) {
1079                                 if (!sid_peek_check_rid
1080                                     (get_global_sam_sid (), &map.sid, &rid))
1081                                         return False;
1082                         } else
1083                                 rid = pdb_gid_to_group_rid (pdb_get_gid
1084                                                             (sampass));
1085                 }
1086
1087                 slprintf (group_rid, sizeof (group_rid) - 1, "%u", rid);
1088         }
1089
1090         acb = pdb_encode_acct_ctrl (pdb_get_acct_ctrl (sampass),
1091                                     NEW_PW_FORMAT_SPACE_PADDED_LEN);
1092         pdb_sethexpwd (smb_passwd, pdb_get_lanman_passwd (sampass),
1093                        pdb_get_acct_ctrl (sampass));
1094         pdb_sethexpwd (smb_nt_passwd, pdb_get_nt_passwd (sampass),
1095                        pdb_get_acct_ctrl (sampass));
1096         slprintf (logon_t, 13, "LNT-%08X",
1097                   (uint32) pdb_get_logon_time (sampass));
1098         slprintf (logoff_t, 13, "LOT-%08X",
1099                   (uint32) pdb_get_logoff_time (sampass));
1100         slprintf (kickoff_t, 13, "KOT-%08X",
1101                   (uint32) pdb_get_kickoff_time (sampass));
1102         slprintf (pwdlset_t, 13, "LCT-%08X",
1103                   (uint32) pdb_get_pass_last_set_time (sampass));
1104         slprintf (pwdlchg_t, 13, "CCT-%08X",
1105                   (uint32) pdb_get_pass_can_change_time (sampass));
1106         slprintf (pwdmchg_t, 13, "MCT-%08X",
1107                   (uint32) pdb_get_pass_must_change_time (sampass));
1108         safe_strcpy (full_name, pdb_get_fullname (sampass),
1109                      sizeof (full_name) - 1);
1110         safe_strcpy (acct_desc, pdb_get_acct_desc (sampass),
1111                      sizeof (acct_desc) - 1);
1112
1113 #if 0
1114
1115         /* Not sure what to do with these guys. -tpot */
1116
1117         dos_to_unix (full_name, True);
1118         dos_to_unix (acct_desc, True);
1119
1120 #endif
1121
1122         if (old) {
1123                 /* name */
1124                 if (strcmp (ENTRY_VAL (old, NPF_NAME), name)) {
1125                         need_to_modify = True;
1126                         set_single_attribute (obj, NPF_NAME, name,
1127                                               strlen (name), EN_MODIFIED);
1128                 }
1129
1130
1131                 /* uid */
1132                 if (pdb_get_uid (sampass) != -1) {
1133                         if (!ENTRY_VAL (old, NPF_UID)
1134                             || strcmp (ENTRY_VAL (old, NPF_UID), uid)) {
1135                                 need_to_modify = True;
1136                                 set_single_attribute (obj, NPF_UID, uid,
1137                                                       strlen (uid),
1138                                                       EN_MODIFIED);
1139                         }
1140                 }
1141
1142                 /* user_rid */
1143                 if (pdb_get_user_rid (sampass)) {
1144                         if (!ENTRY_VAL (old, NPF_USER_RID) ||
1145                             strcmp (ENTRY_VAL (old, NPF_USER_RID),
1146                                     user_rid)) {
1147                                 need_to_modify = True;
1148                                 set_single_attribute (obj, NPF_USER_RID,
1149                                                       user_rid,
1150                                                       strlen (user_rid),
1151                                                       EN_MODIFIED);
1152                         }
1153                 }
1154
1155                 /* smb_grpid */
1156                 if (pdb_get_gid (sampass) != -1) {
1157                         if (!ENTRY_VAL (old, NPF_SMB_GRPID) ||
1158                             strcmp (ENTRY_VAL (old, NPF_SMB_GRPID), gid)) {
1159                                 need_to_modify = True;
1160                                 set_single_attribute (obj, NPF_SMB_GRPID, gid,
1161                                                       strlen (gid),
1162                                                       EN_MODIFIED);
1163                         }
1164                 }
1165
1166                 /* group_rid */
1167                 if (pdb_get_group_rid (sampass)) {
1168                         if (!ENTRY_VAL (old, NPF_GROUP_RID) ||
1169                             strcmp (ENTRY_VAL (old, NPF_GROUP_RID),
1170                                     group_rid)) {
1171                                 need_to_modify = True;
1172                                 set_single_attribute (obj, NPF_GROUP_RID,
1173                                                       group_rid,
1174                                                       strlen (group_rid),
1175                                                       EN_MODIFIED);
1176                         }
1177                 }
1178
1179                 /* acb */
1180                 if (!ENTRY_VAL (old, NPF_ACB) ||
1181                     strcmp (ENTRY_VAL (old, NPF_ACB), acb)) {
1182                         need_to_modify = True;
1183                         set_single_attribute (obj, NPF_ACB, acb, strlen (acb),
1184                                               EN_MODIFIED);
1185                 }
1186
1187                 /* lmpwd */
1188                 if (!ENTRY_VAL (old, NPF_LMPWD) ||
1189                     strcmp (ENTRY_VAL (old, NPF_LMPWD), smb_passwd)) {
1190                         need_to_modify = True;
1191                         set_single_attribute (obj, NPF_LMPWD, smb_passwd,
1192                                               strlen (smb_passwd),
1193                                               EN_CRYPT | EN_MODIFIED);
1194                 }
1195
1196                 /* ntpwd */
1197                 if (!ENTRY_VAL (old, NPF_NTPWD) ||
1198                     strcmp (ENTRY_VAL (old, NPF_NTPWD), smb_nt_passwd)) {
1199                         need_to_modify = True;
1200                         set_single_attribute (obj, NPF_NTPWD, smb_nt_passwd,
1201                                               strlen (smb_nt_passwd),
1202                                               EN_CRYPT | EN_MODIFIED);
1203                 }
1204
1205                 /* logon_t */
1206                 if (pdb_get_logon_time (sampass) &&
1207                     (!ENTRY_VAL (old, NPF_LOGON_T) ||
1208                      strcmp (ENTRY_VAL (old, NPF_LOGON_T), logon_t))) {
1209                         need_to_modify = True;
1210                         set_single_attribute (obj, NPF_LOGON_T, logon_t,
1211                                               strlen (logon_t), EN_MODIFIED);
1212                 }
1213
1214                 /* logoff_t */
1215                 if (pdb_get_logoff_time (sampass) &&
1216                     (!ENTRY_VAL (old, NPF_LOGOFF_T) ||
1217                      strcmp (ENTRY_VAL (old, NPF_LOGOFF_T), logoff_t))) {
1218                         need_to_modify = True;
1219                         set_single_attribute (obj, NPF_LOGOFF_T, logoff_t,
1220                                               strlen (logoff_t), EN_MODIFIED);
1221                 }
1222
1223                 /* kick_t */
1224                 if (pdb_get_kickoff_time (sampass) &&
1225                     (!ENTRY_VAL (old, NPF_KICK_T) ||
1226                      strcmp (ENTRY_VAL (old, NPF_KICK_T), kickoff_t))) {
1227                         need_to_modify = True;
1228                         set_single_attribute (obj, NPF_KICK_T, kickoff_t,
1229                                               strlen (kickoff_t),
1230                                               EN_MODIFIED);
1231                 }
1232
1233                 /* pwdlset_t */
1234                 if (pdb_get_pass_last_set_time (sampass) &&
1235                     (!ENTRY_VAL (old, NPF_PWDLSET_T) ||
1236                      strcmp (ENTRY_VAL (old, NPF_PWDLSET_T), pwdlset_t))) {
1237                         need_to_modify = True;
1238                         set_single_attribute (obj, NPF_PWDLSET_T, pwdlset_t,
1239                                               strlen (pwdlset_t),
1240                                               EN_MODIFIED);
1241                 }
1242
1243                 /* pwdlchg_t */
1244                 if (pdb_get_pass_can_change_time (sampass) &&
1245                     (!ENTRY_VAL (old, NPF_PWDCCHG_T) ||
1246                      strcmp (ENTRY_VAL (old, NPF_PWDCCHG_T), pwdlchg_t))) {
1247                         need_to_modify = True;
1248                         set_single_attribute (obj, NPF_PWDCCHG_T, pwdlchg_t,
1249                                               strlen (pwdlchg_t),
1250                                               EN_MODIFIED);
1251                 }
1252
1253                 /* pwdmchg_t */
1254                 if (pdb_get_pass_must_change_time (sampass) &&
1255                     (!ENTRY_VAL (old, NPF_PWDMCHG_T) ||
1256                      strcmp (ENTRY_VAL (old, NPF_PWDMCHG_T), pwdmchg_t))) {
1257                         need_to_modify = True;
1258                         set_single_attribute (obj, NPF_PWDMCHG_T, pwdmchg_t,
1259                                               strlen (pwdmchg_t),
1260                                               EN_MODIFIED);
1261                 }
1262
1263                 /* full_name */
1264                 /* must support set, unset and change */
1265                 if ((pdb_get_fullname (sampass) &&
1266                      !ENTRY_VAL (old, NPF_FULL_NAME)) ||
1267                     (ENTRY_VAL (old, NPF_FULL_NAME) &&
1268                      !pdb_get_fullname (sampass)) ||
1269                     (ENTRY_VAL (old, NPF_FULL_NAME) &&
1270                      pdb_get_fullname (sampass) &&
1271                      strcmp (ENTRY_VAL (old, NPF_FULL_NAME), full_name))) {
1272                         need_to_modify = True;
1273                         set_single_attribute (obj, NPF_FULL_NAME, full_name,
1274                                               strlen (full_name),
1275                                               EN_MODIFIED);
1276                 }
1277
1278                 /* home_dir */
1279                 /* must support set, unset and change */
1280                 if ((pdb_get_homedir (sampass) &&
1281                      !ENTRY_VAL (old, NPF_HOME_DIR)) ||
1282                     (ENTRY_VAL (old, NPF_HOME_DIR) &&
1283                      !pdb_get_homedir (sampass)) ||
1284                     (ENTRY_VAL (old, NPF_HOME_DIR) &&
1285                      pdb_get_homedir (sampass) &&
1286                      strcmp (ENTRY_VAL (old, NPF_HOME_DIR),
1287                              pdb_get_homedir (sampass)))) {
1288                         need_to_modify = True;
1289                         set_single_attribute (obj, NPF_HOME_DIR,
1290                                               pdb_get_homedir (sampass),
1291                                               strlen (pdb_get_homedir
1292                                                       (sampass)),
1293                                               EN_MODIFIED);
1294                 }
1295
1296                 /* dir_drive */
1297                 /* must support set, unset and change */
1298                 if ((pdb_get_dir_drive (sampass) &&
1299                      !ENTRY_VAL (old, NPF_DIR_DRIVE)) ||
1300                     (ENTRY_VAL (old, NPF_DIR_DRIVE) &&
1301                      !pdb_get_dir_drive (sampass)) ||
1302                     (ENTRY_VAL (old, NPF_DIR_DRIVE) &&
1303                      pdb_get_dir_drive (sampass) &&
1304                      strcmp (ENTRY_VAL (old, NPF_DIR_DRIVE),
1305                              pdb_get_dir_drive (sampass)))) {
1306                         need_to_modify = True;
1307                         set_single_attribute (obj, NPF_DIR_DRIVE,
1308                                               pdb_get_dir_drive (sampass),
1309                                               strlen (pdb_get_dir_drive
1310                                                       (sampass)),
1311                                               EN_MODIFIED);
1312                 }
1313
1314                 /* logon_script */
1315                 /* must support set, unset and change */
1316                 if (((pdb_get_logon_script (sampass) &&
1317                       !ENTRY_VAL (old, NPF_LOGON_SCRIPT)) ||
1318                      ((ENTRY_VAL (old, NPF_LOGON_SCRIPT) &&
1319                        (!pdb_get_logon_script (sampass)))) ||
1320                      ((ENTRY_VAL (old, NPF_LOGON_SCRIPT) &&
1321                        pdb_get_logon_script (sampass) &&
1322                        strcmp (ENTRY_VAL (old, NPF_LOGON_SCRIPT),
1323                                pdb_get_logon_script (sampass)))))) {
1324                         need_to_modify = True;
1325                         set_single_attribute (obj, NPF_LOGON_SCRIPT,
1326                                               pdb_get_logon_script (sampass),
1327                                               strlen (pdb_get_logon_script
1328                                                       (sampass)),
1329                                               EN_MODIFIED);
1330                 }
1331
1332                 /* profile_path */
1333                 /* must support set, unset and change */
1334                 if ((pdb_get_profile_path (sampass) &&
1335                      !ENTRY_VAL (old, NPF_PROFILE_PATH)) ||
1336                     (ENTRY_VAL (old, NPF_PROFILE_PATH) &&
1337                      !pdb_get_profile_path (sampass)) ||
1338                     (ENTRY_VAL (old, NPF_PROFILE_PATH) &&
1339                      pdb_get_profile_path (sampass) &&
1340                      strcmp (ENTRY_VAL (old, NPF_PROFILE_PATH),
1341                              pdb_get_profile_path (sampass)))) {
1342                         need_to_modify = True;
1343                         set_single_attribute (obj, NPF_PROFILE_PATH,
1344                                               pdb_get_profile_path (sampass),
1345                                               strlen (pdb_get_profile_path
1346                                                       (sampass)),
1347                                               EN_MODIFIED);
1348                 }
1349
1350                 /* acct_desc */
1351                 /* must support set, unset and change */
1352                 if ((pdb_get_acct_desc (sampass) &&
1353                      !ENTRY_VAL (old, NPF_ACCT_DESC)) ||
1354                     (ENTRY_VAL (old, NPF_ACCT_DESC) &&
1355                      !pdb_get_acct_desc (sampass)) ||
1356                     (ENTRY_VAL (old, NPF_ACCT_DESC) &&
1357                      pdb_get_acct_desc (sampass) &&
1358                      strcmp (ENTRY_VAL (old, NPF_ACCT_DESC), acct_desc))) {
1359                         need_to_modify = True;
1360                         set_single_attribute (obj, NPF_ACCT_DESC, acct_desc,
1361                                               strlen (acct_desc),
1362                                               EN_MODIFIED);
1363                 }
1364
1365                 /* workstations */
1366                 /* must support set, unset and change */
1367                 if ((pdb_get_workstations (sampass) &&
1368                      !ENTRY_VAL (old, NPF_WORKSTATIONS)) ||
1369                     (ENTRY_VAL (old, NPF_WORKSTATIONS) &&
1370                      !pdb_get_workstations (sampass)) ||
1371                     (ENTRY_VAL (old, NPF_WORKSTATIONS) &&
1372                      (pdb_get_workstations (sampass)) &&
1373                      strcmp (ENTRY_VAL (old, NPF_WORKSTATIONS),
1374                              pdb_get_workstations (sampass)))) {
1375                         need_to_modify = True;
1376                         set_single_attribute (obj, NPF_WORKSTATIONS,
1377                                               pdb_get_workstations (sampass),
1378                                               strlen (pdb_get_workstations
1379                                                       (sampass)),
1380                                               EN_MODIFIED);
1381                 }
1382
1383                 /* hours */
1384                 if ((pdb_get_hours_len (sampass) !=
1385                      ENTRY_LEN (old, NPF_HOURS))
1386                     || memcmp (pdb_get_hours (sampass),
1387                                ENTRY_VAL (old, NPF_HOURS), ENTRY_LEN (old,
1388                                                                       NPF_HOURS)))
1389                 {
1390                         need_to_modify = True;
1391                         /* set_single_attribute will add 1 for len ... */
1392                         set_single_attribute (obj, NPF_HOURS,
1393                                               pdb_get_hours (sampass),
1394                                               pdb_get_hours_len (sampass) - 1,
1395                                               EN_MODIFIED);
1396                 }
1397         } else {
1398                 const char *homedir, *dirdrive, *logon_script, *profile_path,
1399                         *workstations;
1400
1401                 *empty = '\0';  /* empty string */
1402
1403                 set_single_attribute (obj, NPF_NAME, name, strlen (name), 0);
1404                 set_single_attribute (obj, NPF_UID, uid, strlen (uid), 0);
1405                 set_single_attribute (obj, NPF_USER_RID, user_rid,
1406                                       strlen (user_rid), 0);
1407                 set_single_attribute (obj, NPF_SMB_GRPID, gid, strlen (gid),
1408                                       0);
1409                 set_single_attribute (obj, NPF_GROUP_RID, group_rid,
1410                                       strlen (group_rid), 0);
1411                 set_single_attribute (obj, NPF_ACB, acb, strlen (acb), 0);
1412                 set_single_attribute (obj, NPF_LMPWD, smb_passwd,
1413                                       strlen (smb_passwd), EN_CRYPT);
1414                 set_single_attribute (obj, NPF_NTPWD, smb_nt_passwd,
1415                                       strlen (smb_nt_passwd), EN_CRYPT);
1416                 set_single_attribute (obj, NPF_LOGON_T, logon_t,
1417                                       strlen (logon_t), 0);
1418                 set_single_attribute (obj, NPF_LOGOFF_T, logoff_t,
1419                                       strlen (logoff_t), 0);
1420                 set_single_attribute (obj, NPF_KICK_T, kickoff_t,
1421                                       strlen (kickoff_t), 0);
1422                 set_single_attribute (obj, NPF_PWDLSET_T, pwdlset_t,
1423                                       strlen (pwdlset_t), 0);
1424                 set_single_attribute (obj, NPF_PWDCCHG_T, pwdlchg_t,
1425                                       strlen (pwdlchg_t), 0);
1426                 set_single_attribute (obj, NPF_PWDMCHG_T, pwdmchg_t,
1427                                       strlen (pwdmchg_t), 0);
1428                 set_single_attribute (obj, NPF_FULL_NAME,
1429                                       full_name, strlen (full_name), 0);
1430
1431                 if (!(homedir = pdb_get_homedir (sampass)))
1432                         homedir = empty;
1433
1434                 set_single_attribute (obj, NPF_HOME_DIR,
1435                                       homedir, strlen (homedir), 0);
1436
1437                 if (!(dirdrive = pdb_get_dir_drive (sampass)))
1438                         dirdrive = empty;
1439
1440                 set_single_attribute (obj, NPF_DIR_DRIVE,
1441                                       dirdrive, strlen (dirdrive), 0);
1442
1443                 if (!(logon_script = pdb_get_logon_script (sampass)))
1444                         logon_script = empty;
1445
1446                 set_single_attribute (obj, NPF_LOGON_SCRIPT,
1447                                       logon_script, strlen (logon_script), 0);
1448
1449                 if (!(profile_path = pdb_get_profile_path (sampass)))
1450                         profile_path = empty;
1451
1452                 set_single_attribute (obj, NPF_PROFILE_PATH,
1453                                       profile_path, strlen (profile_path), 0);
1454
1455                 set_single_attribute (obj, NPF_ACCT_DESC,
1456                                       acct_desc, strlen (acct_desc), 0);
1457
1458                 if (!(workstations = pdb_get_workstations (sampass)))
1459                         workstations = empty;
1460
1461                 set_single_attribute (obj, NPF_WORKSTATIONS,
1462                                       workstations, strlen (workstations), 0);
1463
1464                 /* set_single_attribute will add 1 for len ... */
1465                 set_single_attribute (obj, NPF_HOURS,
1466                                       pdb_get_hours (sampass),
1467                                       pdb_get_hours_len (sampass) - 1, 0);
1468         }
1469
1470         return need_to_modify;
1471 }
1472
1473 /***************************************************************
1474  calls nis_list, returns results.
1475  ****************************************************************/
1476 static nis_result *nisp_get_nis_list (const char *nisname, unsigned int flags)
1477 {
1478         nis_result *result;
1479         int i;
1480
1481         if (!flags)
1482                 flags = FOLLOW_LINKS | FOLLOW_PATH | EXPAND_NAME |
1483                         HARD_LOOKUP;
1484
1485         for (i = 0; i < 2; i++) {
1486                 alarm (60);     /* hopefully ok for long searches */
1487                 result = nis_list (nisname, flags, NULL, NULL);
1488
1489                 alarm (0);
1490                 CatchSignal (SIGALRM, SIGNAL_CAST SIG_DFL);
1491
1492                 if (!(flags & MASTER_ONLY) && NIS_RES_NUMOBJ (result) <= 0) {
1493                         /* nis replicas are not in sync perhaps?
1494                          * this can happen, if account was just added.
1495                          */
1496                         DEBUG (10, ("will try master only\n"));
1497                         nis_freeresult (result);
1498                         flags |= MASTER_ONLY;
1499                 } else
1500                         break;
1501         }
1502         return result;
1503 }
1504
1505 NTSTATUS pdb_init_nisplussam (PDB_CONTEXT * pdb_context,
1506                               PDB_METHODS ** pdb_method, const char *location)
1507 {
1508         NTSTATUS nt_status;
1509         struct nisplus_private_info *private = malloc (sizeof (struct nisplus_private_info));
1510
1511         ZERO_STRUCT(private);
1512         p->location = talloc_strdup(pdb_context->mem_ctx, location);
1513
1514         if (!NT_STATUS_IS_OK
1515             (nt_status =
1516              make_pdb_methods (pdb_context->mem_ctx, pdb_method))) {
1517                 return nt_status;
1518         }
1519
1520         (*pdb_method)->name = "nisplussam";
1521
1522         /* Functions your pdb module doesn't provide should be set 
1523          * to NULL */
1524
1525         (*pdb_method)->setsampwent = nisplussam_setsampwent;
1526         (*pdb_method)->endsampwent = nisplussam_endsampwent;
1527         (*pdb_method)->getsampwent = nisplussam_getsampwent;
1528         (*pdb_method)->getsampwnam = nisplussam_getsampwnam;
1529         (*pdb_method)->getsampwsid = nisplussam_getsampwsid;
1530         (*pdb_method)->add_sam_account = nisplussam_add_sam_account;
1531         (*pdb_method)->update_sam_account = nisplussam_update_sam_account;
1532         (*pdb_method)->delete_sam_account = nisplussam_delete_sam_account;
1533         (*pdb_method)->private_data = private;
1534
1535         return NT_STATUS_OK;
1536 }
1537
1538 #else
1539 NTSTATUS pdb_init_nisplussam (PDB_CONTEXT * c, PDB_METHODS ** m,
1540                               const char *l)
1541 {
1542         DEBUG (0, ("nisplus sam not compiled in!\n"));
1543         return NT_STATUS_UNSUCCESSFUL;
1544 }
1545 #endif /* WITH_NISPLUS_SAM */