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