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