first pass at updating head branch to be to be the same as the SAMBA_2_0 branch
[kai/samba.git] / source3 / passdb / nispass.c
1 /*
2  * Unix SMB/Netbios implementation. Version 1.9. SMB parameters and setup
3  * Copyright (C) Andrew Tridgell 1992-1998 Modified by Jeremy Allison 1995.
4  * Copyright (C) Benny Holmgren 1998 <bigfoot@astrakan.hgs.se> 
5  * Copyright (C) Luke Kenneth Casson Leighton 1996-1998.
6  * 
7  * This program is free software; you can redistribute it and/or modify it under
8  * the terms of the GNU General Public License as published by the Free
9  * Software Foundation; either version 2 of the License, or (at your option)
10  * any later version.
11  * 
12  * This program is distributed in the hope that it will be useful, but WITHOUT
13  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
14  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
15  * more details.
16  * 
17  * You should have received a copy of the GNU General Public License along with
18  * this program; if not, write to the Free Software Foundation, Inc., 675
19  * Mass Ave, Cambridge, MA 02139, USA.
20  */
21
22 #include "includes.h"
23
24 #ifdef WITH_NISPLUS
25
26 #ifdef BROKEN_NISPLUS_INCLUDE_FILES
27
28 /*
29  * The following lines are needed due to buggy include files
30  * in Solaris 2.6 which define GROUP in both /usr/include/sys/acl.h and
31  * also in /usr/include/rpcsvc/nis.h. The definitions conflict. JRA.
32  * Also GROUP_OBJ is defined as 0x4 in /usr/include/sys/acl.h and as
33  * an enum in /usr/include/rpcsvc/nis.h.
34  */
35
36 #if defined(GROUP)
37 #undef GROUP
38 #endif
39
40 #if defined(GROUP_OBJ)
41 #undef GROUP_OBJ
42 #endif
43
44 #endif
45
46 #include <rpcsvc/nis.h>
47
48 extern int      DEBUGLEVEL;
49 extern pstring samlogon_user;
50 extern BOOL sam_logon_in_ssb;
51
52 static VOLATILE SIG_ATOMIC_T gotalarm;
53
54 /***************************************************************
55
56  the fields for the NIS+ table, generated from mknissmbpwtbl.sh, are:
57
58         name=S,nogw=r 
59         uid=S,nogw=r 
60                 user_rid=S,nogw=r
61                 smb_grpid=,nw+r
62                 group_rid=,nw+r
63                 acb=,nw+r
64                           
65         lmpwd=C,nw=,g=r,o=rm 
66         ntpwd=C,nw=,g=r,o=rm 
67                                      
68                 logon_t=,nw+r 
69                 logoff_t=,nw+r 
70                 kick_t=,nw+r 
71                 pwdlset_t=,nw+r 
72                 pwdlchg_t=,nw+r 
73                 pwdmchg_t=,nw+r 
74                                 
75                 full_name=,nw+r 
76                 home_dir=,nw+r 
77                 dir_drive=,nw+r 
78                 logon_script=,nw+r 
79                 profile_path=,nw+r 
80                 acct_desc=,nw+r 
81                 workstations=,nw+r 
82                                    
83                 hours=,nw+r 
84
85 ****************************************************************/
86
87 #define NPF_NAME          0
88 #define NPF_UID           1
89 #define NPF_USER_RID      2
90 #define NPF_SMB_GRPID     3
91 #define NPF_GROUP_RID     4
92 #define NPF_ACB           5
93 #define NPF_LMPWD         6
94 #define NPF_NTPWD         7
95 #define NPF_LOGON_T       8
96 #define NPF_LOGOFF_T      9
97 #define NPF_KICK_T        10
98 #define NPF_PWDLSET_T     11
99 #define NPF_PWDLCHG_T     12
100 #define NPF_PWDMCHG_T     13
101 #define NPF_FULL_NAME     14
102 #define NPF_HOME_DIR      15
103 #define NPF_DIR_DRIVE     16
104 #define NPF_LOGON_SCRIPT  17
105 #define NPF_PROFILE_PATH  18
106 #define NPF_ACCT_DESC     19
107 #define NPF_WORKSTATIONS  20
108 #define NPF_HOURS         21
109
110 /***************************************************************
111  Signal function to tell us we timed out.
112 ****************************************************************/
113 static void gotalarm_sig(void)
114 {
115   gotalarm = 1;
116 }
117
118 /***************************************************************
119  make_nisname_from_user_rid
120  ****************************************************************/
121 static char *make_nisname_from_user_rid(uint32 rid, char *pfile)
122 {
123         static pstring nisname;
124
125         safe_strcpy(nisname, "[user_rid=", sizeof(nisname)-1);
126         slprintf(nisname, sizeof(nisname)-1, "%s%d", nisname, rid);
127         safe_strcat(nisname, "],", sizeof(nisname)-strlen(nisname)-1);
128         safe_strcat(nisname, pfile, sizeof(nisname)-strlen(nisname)-1);
129
130         return nisname;
131 }
132
133 /***************************************************************
134  make_nisname_from_uid
135  ****************************************************************/
136 static char *make_nisname_from_uid(int uid, char *pfile)
137 {
138         static pstring nisname;
139
140         safe_strcpy(nisname, "[uid=", sizeof(nisname)-1);
141         slprintf(nisname, sizeof(nisname)-1, "%s%d", nisname, uid);
142         safe_strcat(nisname, "],", sizeof(nisname)-strlen(nisname)-1);
143         safe_strcat(nisname, pfile, sizeof(nisname)-strlen(nisname)-1);
144
145         return nisname;
146 }
147
148 /***************************************************************
149  make_nisname_from_name
150  ****************************************************************/
151 static char *make_nisname_from_name(char *user_name, char *pfile)
152 {
153         static pstring nisname;
154
155         safe_strcpy(nisname, "[name=", sizeof(nisname)-1);
156         safe_strcat(nisname, user_name, sizeof(nisname) - strlen(nisname) - 1);
157         safe_strcat(nisname, "],", sizeof(nisname)-strlen(nisname)-1);
158         safe_strcat(nisname, pfile, sizeof(nisname)-strlen(nisname)-1);
159
160         return nisname;
161 }
162
163 /*************************************************************************
164  gets a NIS+ attribute
165  *************************************************************************/
166 static void get_single_attribute(nis_object *new_obj, int col,
167                                 char *val, int len)
168 {
169         int entry_len;
170
171         if (new_obj == NULL || val == NULL) return;
172         
173         entry_len = ENTRY_LEN(new_obj, col);
174         if (len > entry_len)
175         {
176                 DEBUG(10,("get_single_attribute: entry length truncated\n"));
177                 len = entry_len;
178         }
179
180         safe_strcpy(val, ENTRY_VAL(new_obj, col), len-1);
181 }
182
183 /************************************************************************
184  makes a struct sam_passwd from a NIS+ object.
185  ************************************************************************/
186 static BOOL make_sam_from_nisp_object(struct sam_passwd *pw_buf, nis_object *obj)
187 {
188         int uidval;
189         static pstring user_name;
190         static pstring full_name;
191         static pstring home_dir;
192         static pstring home_drive;
193         static pstring logon_script;
194         static pstring profile_path;
195         static pstring acct_desc;
196         static pstring workstations;
197         static pstring temp;
198         static unsigned char smbpwd[16];
199         static unsigned char smbntpwd[16];
200         
201         char *p;
202
203         pdb_init_sam(pw_buf);
204         pw_buf->acct_ctrl = ACB_NORMAL;
205
206         pstrcpy(user_name, ENTRY_VAL(obj, NPF_NAME));
207         pw_buf->smb_name      = user_name;
208
209         uidval = atoi(ENTRY_VAL(obj, NPF_UID));
210         pw_buf->smb_userid    = uidval;         
211
212         /* Check the lanman password column. */
213         p = (char *)ENTRY_VAL(obj, NPF_LMPWD);
214         if (*p == '*' || *p == 'X') {
215           /* Password deliberately invalid - end here. */
216           DEBUG(10, ("make_sam_from_nisp_object: entry invalidated for user %s\n", user_name));
217           pw_buf->smb_nt_passwd = NULL;
218           pw_buf->smb_passwd = NULL;
219           pw_buf->acct_ctrl |= ACB_DISABLED;
220           return True;
221         }
222         if (!strncasecmp(p, "NO PASSWORD", 11)) {
223           pw_buf->smb_passwd = NULL;
224           pw_buf->acct_ctrl |= ACB_PWNOTREQ;
225         } else {
226           if (strlen(p) != 32 || !pdb_gethexpwd(p, smbpwd))
227             {
228               DEBUG(0, ("make_sam_from_nisp_object: malformed LM pwd entry.\n"));
229               return False;
230             }
231         }
232
233         pw_buf->smb_passwd    = smbpwd;
234
235         /* Check the NT password column. */
236         p = ENTRY_VAL(obj, NPF_NTPWD);
237         if (*p != '*' && *p != 'X') {
238           if (strlen(p) != 32 || !pdb_gethexpwd(p, smbntpwd))
239             {
240               DEBUG(0, ("make_smb_from_nisp_object: malformed NT pwd entry\n"));
241               return False;
242             }
243           pw_buf->smb_nt_passwd = smbntpwd;
244         }
245
246         p = (char *)ENTRY_VAL(obj, NPF_ACB);
247         if (*p == '[')
248           {
249             pw_buf->acct_ctrl = pdb_decode_acct_ctrl(p);
250             
251             /* Must have some account type set. */
252             if(pw_buf->acct_ctrl == 0)
253               pw_buf->acct_ctrl = ACB_NORMAL;
254             
255             /* Now try and get the last change time. */
256             if(*p == ']')
257               p++;
258             if(*p == ':') {
259               p++;
260               if(*p && (StrnCaseCmp(p, "LCT-", 4)==0)) {
261                 int i;
262                 p += 4;
263                 for(i = 0; i < 8; i++) {
264                   if(p[i] == '\0' || !isxdigit(p[i]))
265                     break;
266                 }
267                 if(i == 8) {
268                   /*
269                    * p points at 8 characters of hex digits - 
270                    * read into a time_t as the seconds since
271                    * 1970 that the password was last changed.
272                    */
273                   pw_buf->pass_last_set_time = (time_t)strtol(p, NULL, 16);
274                 }
275               }
276             }
277         } else {
278           /* 'Old' style file. Fake up based on user name. */
279           /*
280            * Currently trust accounts are kept in the same
281            * password file as 'normal accounts'. If this changes
282            * we will have to fix this code. JRA.
283            */
284           if(pw_buf->smb_name[strlen(pw_buf->smb_name) - 1] == '$') {
285             pw_buf->acct_ctrl &= ~ACB_NORMAL;
286             pw_buf->acct_ctrl |= ACB_WSTRUST;
287           }
288         }
289
290         get_single_attribute(obj, NPF_SMB_GRPID, temp, sizeof(pstring));
291         pw_buf->smb_grpid = atoi(temp);
292
293         get_single_attribute(obj, NPF_USER_RID, temp, sizeof(pstring));
294         pw_buf->user_rid = (strlen(temp) > 0) ?
295           strtol(temp, NULL, 16) : pdb_uid_to_user_rid (pw_buf->smb_userid);
296
297         if (pw_buf->smb_name[strlen(pw_buf->smb_name)-1] != '$') {
298           
299           /* XXXX hack to get standard_sub_basic() to use sam logon username */
300           /* possibly a better way would be to do a become_user() call */
301           pstrcpy(samlogon_user, pw_buf->smb_name);
302           sam_logon_in_ssb = True;
303           
304           get_single_attribute(obj, NPF_GROUP_RID, temp, sizeof(pstring));
305           pw_buf->group_rid = (strlen(temp) > 0) ?
306             strtol(temp, NULL, 16) : pdb_gid_to_group_rid (pw_buf->smb_grpid);
307           
308           get_single_attribute(obj, NPF_FULL_NAME, full_name, sizeof(pstring));
309 #if 1
310           /* It seems correct to use the global values - but in that case why
311            * do we want these NIS+ entries anyway ??
312            */
313           pstrcpy(logon_script , lp_logon_script       ());
314           pstrcpy(profile_path , lp_logon_path         ());
315           pstrcpy(home_drive   , lp_logon_drive        ());
316           pstrcpy(home_dir     , lp_logon_home         ());
317 #else
318           get_single_attribute(obj, NPF_LOGON_SCRIPT, logon_script, sizeof(pstring));
319           get_single_attribute(obj, NPF_PROFILE_PATH, profile_path, sizeof(pstring));
320           get_single_attribute(obj, NPF_DIR_DRIVE, home_drive, sizeof(pstring));
321           get_single_attribute(obj, NPF_HOME_DIR, home_dir, sizeof(pstring));
322 #endif
323           get_single_attribute(obj, NPF_ACCT_DESC, acct_desc, sizeof(pstring));
324           get_single_attribute(obj, NPF_WORKSTATIONS, workstations, sizeof(pstring));
325           
326           sam_logon_in_ssb = False;
327
328         } else {
329           
330           pw_buf->group_rid = DOMAIN_GROUP_RID_USERS; /* lkclXXXX this is OBSERVED behaviour by NT PDCs, enforced here. */
331           
332           pstrcpy(full_name    , "");
333           pstrcpy(logon_script , "");
334           pstrcpy(profile_path , "");
335           pstrcpy(home_drive   , "");
336           pstrcpy(home_dir     , "");
337           pstrcpy(acct_desc    , "");
338           pstrcpy(workstations , "");
339         }
340
341         pw_buf->full_name    = full_name;
342         pw_buf->home_dir     = home_dir;
343         pw_buf->dir_drive    = home_drive;
344         pw_buf->logon_script = logon_script;
345         pw_buf->profile_path = profile_path;
346         pw_buf->acct_desc    = acct_desc;
347         pw_buf->workstations = workstations;
348
349         pw_buf->unknown_str = NULL; /* don't know, yet! */
350         pw_buf->munged_dial = NULL; /* "munged" dial-back telephone number */
351
352         pw_buf->unknown_3 = 0xffffff; /* don't know */
353         pw_buf->logon_divs = 168; /* hours per week */
354         pw_buf->hours_len = 21; /* 21 times 8 bits = 168 */
355         memset(pw_buf->hours, 0xff, pw_buf->hours_len); /* available at all hours */
356         pw_buf->unknown_5 = 0x00020000; /* don't know */
357         pw_buf->unknown_6 = 0x000004ec; /* don't know */
358
359         return True;
360 }
361
362 /************************************************************************
363  makes a struct sam_passwd from a NIS+ result.
364  ************************************************************************/
365 static BOOL make_sam_from_nisresult(struct sam_passwd *pw_buf, nis_result *result)
366 {
367         if (pw_buf == NULL || result == NULL) return False;
368
369         if (result->status != NIS_SUCCESS && result->status != NIS_NOTFOUND)
370         {
371                 DEBUG(0, ("make_sam_from_nisresult: NIS+ lookup failure: %s\n",
372                            nis_sperrno(result->status)));
373                 return False;
374         }
375
376         /* User not found. */
377         if (NIS_RES_NUMOBJ(result) <= 0)
378         {
379                 DEBUG(10, ("make_sam_from_nisresult: user not found in NIS+\n"));
380                 return False;
381         }
382
383         if (NIS_RES_NUMOBJ(result) > 1)
384         {
385                 DEBUG(10, ("make_sam_from_nisresult: WARNING: Multiple entries for user in NIS+ table!\n"));
386         }
387
388         /* Grab the first hit. */
389         return make_sam_from_nisp_object(pw_buf, &NIS_RES_OBJECT(result)[0]);
390       }
391
392 /***************************************************************
393  calls nis_list, returns results.
394  ****************************************************************/
395 static nis_result *nisp_get_nis_list(char *nis_name)
396 {
397         nis_result *result;
398         result = nis_list(nis_name, FOLLOW_PATH|EXPAND_NAME|HARD_LOOKUP,NULL,NULL);
399
400         alarm(0);
401         CatchSignal(SIGALRM, SIGNAL_CAST SIG_DFL);
402
403         if (gotalarm)
404         {
405                 DEBUG(0,("nisp_get_nis_list: NIS+ lookup time out\n"));
406                 nis_freeresult(result);
407                 return NULL;
408         }
409         return result;
410 }
411
412
413
414 struct nisp_enum_info
415 {
416         nis_result *result;
417         int enum_entry;
418 };
419
420 /***************************************************************
421  Start to enumerate the nisplus passwd list. Returns a void pointer
422  to ensure no modification outside this module.
423
424  do not call this function directly.  use passdb.c instead.
425
426  ****************************************************************/
427 static void *startnisppwent(BOOL update)
428 {
429         static struct nisp_enum_info res;
430         res.result = nisp_get_nis_list(lp_smb_passwd_file());
431         res.enum_entry = 0;
432         return res.result != NULL ? &res : NULL;
433 }
434
435 /***************************************************************
436  End enumeration of the nisplus passwd list.
437 ****************************************************************/
438 static void endnisppwent(void *vp)
439 {
440   struct nisp_enum_info *res = (struct nisp_enum_info *)vp;
441   nis_freeresult(res->result);
442   DEBUG(7,("endnisppwent: freed enumeration list\n"));
443 }
444
445 /*************************************************************************
446  Routine to return the next entry in the nisplus passwd list.
447
448  do not call this function directly.  use passdb.c instead.
449
450  *************************************************************************/
451 static struct sam_passwd *getnisp21pwent(void *vp)
452 {
453   struct nisp_enum_info *res = (struct nisp_enum_info *)vp;
454   static struct sam_passwd pw_buf;
455   int which;
456   BOOL ret;
457   
458   if (res == NULL || (int)(res->enum_entry) < 0 ||
459       (int)(res->enum_entry) > (NIS_RES_NUMOBJ(res->result) - 1)) {
460     ret = False;
461   } else {
462     which = (int)(res->enum_entry);
463     ret = make_sam_from_nisp_object(&pw_buf,
464                  &NIS_RES_OBJECT(res->result)[which]);
465     if (ret && which < (NIS_RES_NUMOBJ(res->result) - 1))
466       (int)(res->enum_entry)++;
467   }
468   
469   return ret ? &pw_buf : NULL;
470 }
471
472 /*************************************************************************
473  Return the current position in the nisplus passwd list as an SMB_BIG_UINT.
474  This must be treated as an opaque token.
475
476  do not call this function directly.  use passdb.c instead.
477
478 *************************************************************************/
479 static SMB_BIG_UINT getnisppwpos(void *vp)
480 {
481   struct nisp_enum_info *res = (struct nisp_enum_info *)vp;
482   return (SMB_BIG_UINT)(res->enum_entry);
483 }
484
485 /*************************************************************************
486  Set the current position in the nisplus passwd list from SMB_BIG_UINT.
487  This must be treated as an opaque token.
488
489  do not call this function directly.  use passdb.c instead.
490
491 *************************************************************************/
492 static BOOL setnisppwpos(void *vp, SMB_BIG_UINT tok)
493 {
494   struct nisp_enum_info *res = (struct nisp_enum_info *)vp;
495   if (tok < (NIS_RES_NUMOBJ(res->result) - 1)) {
496     res->enum_entry = tok;
497     return True;
498   } else {
499     return False;
500   }
501 }
502
503 /*************************************************************************
504  sets a NIS+ attribute
505  *************************************************************************/
506 static void set_single_attribute(nis_object *new_obj, int col,
507                                 char *val, int len, int flags)
508 {
509         if (new_obj == NULL) return;
510
511         ENTRY_VAL(new_obj, col) = val;
512         ENTRY_LEN(new_obj, col) = len+1;
513
514         if (flags != 0)
515         {
516                 new_obj->EN_data.en_cols.en_cols_val[col].ec_flags = flags;
517         }
518 }
519
520 /************************************************************************
521  Routine to add an entry to the nisplus passwd file.
522
523  do not call this function directly.  use passdb.c instead.
524
525 *************************************************************************/
526 static BOOL add_nisp21pwd_entry(struct sam_passwd *newpwd)
527 {
528         char           *pfile;
529         char           *nisname;
530         nis_result      *nis_user;
531         nis_result *result = NULL,
532         *tblresult = NULL, 
533         *addresult = NULL;
534         nis_object new_obj, *obj;
535
536     fstring uid;
537         fstring user_rid;
538         fstring smb_grpid;
539         fstring group_rid;
540         fstring acb;
541                           
542         fstring smb_passwd;
543         fstring smb_nt_passwd;
544
545         fstring logon_t;
546         fstring logoff_t;
547         fstring kickoff_t;
548         fstring pwdlset_t;
549         fstring pwdlchg_t;
550         fstring pwdmchg_t;
551
552         memset((char *)logon_t  , '\0', sizeof(logon_t  ));
553         memset((char *)logoff_t , '\0', sizeof(logoff_t ));
554         memset((char *)kickoff_t, '\0', sizeof(kickoff_t));
555         memset((char *)pwdlset_t, '\0', sizeof(pwdlset_t));
556         memset((char *)pwdlchg_t, '\0', sizeof(pwdlchg_t));
557         memset((char *)pwdmchg_t, '\0', sizeof(pwdmchg_t));
558
559         pfile = lp_smb_passwd_file();
560
561         nisname = make_nisname_from_name(newpwd->smb_name, pfile);
562         result = nisp_get_nis_list(nisname);
563         if (result->status != NIS_SUCCESS && result->status != NIS_NOTFOUND)
564         {
565                 DEBUG(3, ( "add_nis21ppwd_entry: nis_list failure: %s: %s\n",
566                             nisname,  nis_sperrno(result->status)));
567                 nis_freeresult(result);
568                 return False;
569         }   
570
571         if (result->status == NIS_SUCCESS && NIS_RES_NUMOBJ(result) > 0)
572         {
573                 DEBUG(3, ("add_nisp21pwd_entry: User already exists in NIS+ password db: %s\n",
574                             pfile));
575                 nis_freeresult(result);
576                 return False;
577         }
578
579 #if 0
580         /* User not found. */
581         if (!add_user)
582         {
583                 DEBUG(3, ("add_nisp21pwd_entry: User not found in NIS+ password db: %s\n",
584                             pfile));
585                 nis_freeresult(result);
586                 return False;
587         }
588
589 #endif
590
591         tblresult = nis_lookup(pfile, FOLLOW_PATH | EXPAND_NAME | HARD_LOOKUP );
592         if (tblresult->status != NIS_SUCCESS)
593         {
594                 nis_freeresult(result);
595                 nis_freeresult(tblresult);
596                 DEBUG(3, ( "add_nisp21pwd_entry: nis_lookup failure: %s\n",
597                             nis_sperrno(tblresult->status)));
598                 return False;
599         }
600
601         new_obj.zo_name   = NIS_RES_OBJECT(tblresult)->zo_name;
602         new_obj.zo_domain = NIS_RES_OBJECT(tblresult)->zo_domain;
603         new_obj.zo_owner  = NIS_RES_OBJECT(tblresult)->zo_owner;
604         new_obj.zo_group  = NIS_RES_OBJECT(tblresult)->zo_group;
605         new_obj.zo_access = NIS_RES_OBJECT(tblresult)->zo_access;
606         new_obj.zo_ttl    = NIS_RES_OBJECT(tblresult)->zo_ttl;
607
608         new_obj.zo_data.zo_type = ENTRY_OBJ;
609
610         new_obj.zo_data.objdata_u.en_data.en_type = NIS_RES_OBJECT(tblresult)->zo_data.objdata_u.ta_data.ta_type;
611         new_obj.zo_data.objdata_u.en_data.en_cols.en_cols_len = NIS_RES_OBJECT(tblresult)->zo_data.objdata_u.ta_data.ta_maxcol;
612         new_obj.zo_data.objdata_u.en_data.en_cols.en_cols_val = calloc(new_obj.zo_data.objdata_u.en_data.en_cols.en_cols_len, sizeof(entry_col));
613
614         if (new_obj.zo_data.objdata_u.en_data.en_cols.en_cols_val == NULL)
615         {
616                 DEBUG(0, ("add_nisp21pwd_entry: memory allocation failure\n"));
617                 nis_freeresult(result);
618                 nis_freeresult(tblresult);
619                 return False;
620         }
621
622         pdb_sethexpwd(smb_passwd   , newpwd->smb_passwd   , newpwd->acct_ctrl);
623         pdb_sethexpwd(smb_nt_passwd, newpwd->smb_nt_passwd, newpwd->acct_ctrl);
624
625         newpwd->pass_last_set_time = (time_t)time(NULL);
626         newpwd->logon_time = (time_t)-1;
627         newpwd->logoff_time = (time_t)-1;
628         newpwd->kickoff_time = (time_t)-1;
629         newpwd->pass_can_change_time = (time_t)-1;
630         newpwd->pass_must_change_time = (time_t)-1;
631
632         slprintf(logon_t,   13, "LNT-%08X", (uint32)newpwd->logon_time);
633         slprintf(logoff_t,  13, "LOT-%08X", (uint32)newpwd->logoff_time);
634         slprintf(kickoff_t, 13, "KOT-%08X", (uint32)newpwd->kickoff_time);
635         slprintf(pwdlset_t, 13, "LCT-%08X", (uint32)newpwd->pass_last_set_time);
636         slprintf(pwdlchg_t, 13, "CCT-%08X", (uint32)newpwd->pass_can_change_time);
637         slprintf(pwdmchg_t, 13, "MCT-%08X", (uint32)newpwd->pass_must_change_time);
638
639         slprintf(uid, sizeof(uid), "%u", newpwd->smb_userid);
640         slprintf(user_rid, sizeof(user_rid), "0x%x", newpwd->user_rid);
641         slprintf(smb_grpid, sizeof(smb_grpid), "%u", newpwd->smb_grpid);
642         slprintf(group_rid, sizeof(group_rid), "0x%x", newpwd->group_rid);
643
644         safe_strcpy(acb, pdb_encode_acct_ctrl(newpwd->acct_ctrl, NEW_PW_FORMAT_SPACE_PADDED_LEN), sizeof(acb)-1); 
645
646         set_single_attribute(&new_obj, NPF_NAME          , newpwd->smb_name     , strlen(newpwd->smb_name)     , 0);
647         set_single_attribute(&new_obj, NPF_UID           , uid                  , strlen(uid)                  , 0);
648         set_single_attribute(&new_obj, NPF_USER_RID      , user_rid             , strlen(user_rid)             , 0);
649         set_single_attribute(&new_obj, NPF_SMB_GRPID     , smb_grpid            , strlen(smb_grpid)            , 0);
650         set_single_attribute(&new_obj, NPF_GROUP_RID     , group_rid            , strlen(group_rid)            , 0);
651         set_single_attribute(&new_obj, NPF_ACB           , acb                  , strlen(acb)                  , 0);
652         set_single_attribute(&new_obj, NPF_LMPWD         , smb_passwd           , strlen(smb_passwd)           , EN_CRYPT);
653         set_single_attribute(&new_obj, NPF_NTPWD         , smb_nt_passwd        , strlen(smb_nt_passwd)        , EN_CRYPT);
654         set_single_attribute(&new_obj, NPF_LOGON_T       , logon_t              , strlen(logon_t)              , 0);
655         set_single_attribute(&new_obj, NPF_LOGOFF_T      , logoff_t             , strlen(logoff_t)             , 0);
656         set_single_attribute(&new_obj, NPF_KICK_T        , kickoff_t            , strlen(kickoff_t)            , 0);
657         set_single_attribute(&new_obj, NPF_PWDLSET_T     , pwdlset_t            , strlen(pwdlset_t)            , 0);
658         set_single_attribute(&new_obj, NPF_PWDLCHG_T     , pwdlchg_t            , strlen(pwdlchg_t)            , 0);
659         set_single_attribute(&new_obj, NPF_PWDMCHG_T     , pwdmchg_t            , strlen(pwdmchg_t)            , 0);
660 #if 0
661         set_single_attribute(&new_obj, NPF_FULL_NAME     , newpwd->full_name    , strlen(newpwd->full_name)    , 0);
662         set_single_attribute(&new_obj, NPF_HOME_DIR      , newpwd->home_dir     , strlen(newpwd->home_dir)     , 0);
663         set_single_attribute(&new_obj, NPF_DIR_DRIVE     , newpwd->dir_drive    , strlen(newpwd->dir_drive)    , 0);
664         set_single_attribute(&new_obj, NPF_LOGON_SCRIPT  , newpwd->logon_script , strlen(newpwd->logon_script) , 0);
665         set_single_attribute(&new_obj, NPF_PROFILE_PATH  , newpwd->profile_path , strlen(newpwd->profile_path) , 0);
666         set_single_attribute(&new_obj, NPF_ACCT_DESC     , newpwd->acct_desc    , strlen(newpwd->acct_desc)    , 0);
667         set_single_attribute(&new_obj, NPF_WORKSTATIONS  , newpwd->workstations , strlen(newpwd->workstations) , 0);
668         set_single_attribute(&new_obj, NPF_HOURS         , newpwd->hours        , newpwd->hours_len            , 0);
669 #endif
670
671         obj = &new_obj;
672
673         addresult = nis_add_entry(pfile, obj, ADD_OVERWRITE | FOLLOW_PATH | EXPAND_NAME | HARD_LOOKUP);
674
675
676         if (addresult->status != NIS_SUCCESS)
677         {
678                 DEBUG(3, ( "add_nisp21pwd_entry: NIS+ table update failed: %s\n",
679                             nisname, nis_sperrno(addresult->status)));
680                 nis_freeresult(tblresult);
681                 nis_freeresult(addresult);
682                 nis_freeresult(result);
683                 return False;
684         }
685
686         nis_freeresult(tblresult);
687         nis_freeresult(addresult);
688         nis_freeresult(result);
689
690         return True;
691 }
692
693 /************************************************************************
694  Routine to search the nisplus passwd file for an entry matching the username.
695  and then modify its password entry. We can't use the startnisppwent()/
696  getnisppwent()/endnisppwent() interfaces here as we depend on looking
697  in the actual file to decide how much room we have to write data.
698  override = False, normal
699  override = True, override XXXXXXXX'd out password or NO PASS
700
701  do not call this function directly.  use passdb.c instead.
702
703 ************************************************************************/
704 static BOOL mod_nisp21pwd_entry(struct sam_passwd* pwd, BOOL override)
705 {
706   char *oldnislmpwd, *oldnisntpwd, *oldnisacb, *oldnislct, *user_name;
707   char lmpwd[33], ntpwd[33], lct[13];
708   nis_result *result, *addresult;
709   nis_object *obj;
710   fstring acb;
711   pstring nisname;
712   BOOL got_pass_last_set_time, ret;
713   int i;
714   
715   if (!*lp_smb_passwd_file())
716     {
717       DEBUG(0, ("mod_getnisp21pwd_entry: no SMB password file set\n"));
718       return False;
719     }
720   
721   DEBUG(10, ("mod_getnisp21pwd_entry: search by name: %s\n", pwd->smb_name));
722   DEBUG(10, ("mod_getnisp21pwd_entry: using NIS+ table %s\n", lp_smb_passwd_file()));
723   
724   slprintf(nisname, sizeof(nisname)-1, "[name=%s],%s", pwd->smb_name, lp_smb_passwd_file());
725   
726   /* Search the table. */
727   gotalarm = 0;
728   CatchSignal(SIGALRM, SIGNAL_CAST gotalarm_sig);
729   alarm(5);
730   
731   result = nis_list(nisname, FOLLOW_PATH | EXPAND_NAME | HARD_LOOKUP, NULL, NULL);
732   
733   alarm(0);
734   CatchSignal(SIGALRM, SIGNAL_CAST SIG_DFL);
735   
736   if (gotalarm)
737     {
738       DEBUG(0,("mod_getnisp21pwd_entry: NIS+ lookup time out\n"));
739       nis_freeresult(result);
740       return False;
741     }
742   
743   if(result->status != NIS_SUCCESS || NIS_RES_NUMOBJ(result) <= 0) {
744     /* User not found. */
745     DEBUG(0,("mod_getnisp21pwd_entry: user not found in NIS+\n"));
746     nis_freeresult(result);
747     return False;
748   }
749
750   DEBUG(6,("mod_getnisp21pwd_entry: entry exists\n"));
751   
752   obj = NIS_RES_OBJECT(result);
753   
754   user_name = ENTRY_VAL(obj, NPF_NAME);
755   oldnislmpwd = ENTRY_VAL(obj, NPF_LMPWD);
756   oldnisntpwd = ENTRY_VAL(obj, NPF_NTPWD);
757   oldnisacb = ENTRY_VAL(obj, NPF_ACB);
758   oldnislct = ENTRY_VAL(obj, NPF_PWDLSET_T);
759   
760   
761   if (!override && (*oldnislmpwd == '*' || *oldnislmpwd == 'X' ||
762                     *oldnisntpwd == '*' || *oldnisntpwd == 'X')) {
763     /* Password deliberately invalid - end here. */
764     DEBUG(10, ("mod_nisp21pwd_entry: entry invalidated for user %s\n", user_name));
765     nis_freeresult(result);
766     return False;
767   }
768
769   if (strlen(oldnislmpwd) != 32 || strlen(oldnisntpwd) != 32) {
770     DEBUG(0, ("mod_nisp21pwd_entry: malformed password entry (incorrect length)\n"));
771     nis_freeresult(result);
772     return False;
773   }
774
775
776
777   /* 
778    * Now check if the account info and the password last
779    * change time is available.
780    */
781
782   /*
783    * If both NT and lanman passwords are provided - reset password
784    * not required flag.
785    */
786
787   if(pwd->smb_passwd != NULL || pwd->smb_nt_passwd != NULL) {
788     /* Require password in the future (should ACB_DISABLED also be reset?) */
789     pwd->acct_ctrl &= ~(ACB_PWNOTREQ);
790   }
791
792   if (*oldnisacb == '[') {
793     
794     i = 0;
795     acb[i++] = oldnisacb[i];
796     while(i < (sizeof(fstring) - 2) && (oldnisacb[i] != ']'))
797       acb[i] = oldnisacb[i++];
798     
799     acb[i++] = ']';
800     acb[i++] = '\0';
801     
802     if (i == NEW_PW_FORMAT_SPACE_PADDED_LEN) {
803       /*
804        * We are using a new format, space padded
805        * acct ctrl field. Encode the given acct ctrl
806        * bits into it.
807        */
808       fstrcpy(acb, pdb_encode_acct_ctrl(pwd->acct_ctrl, NEW_PW_FORMAT_SPACE_PADDED_LEN));
809     } else {
810       /*
811        * If using the old format and the ACB_DISABLED or
812        * ACB_PWNOTREQ are set then set the lanman and NT passwords to NULL
813        * here as we have no space to encode the change.
814        */
815       if(pwd->acct_ctrl & (ACB_DISABLED|ACB_PWNOTREQ)) {
816         pwd->smb_passwd = NULL;
817         pwd->smb_nt_passwd = NULL;
818       }
819     }
820     
821     /* Now do the LCT stuff. */
822     if (StrnCaseCmp(oldnislct, "LCT-", 4) == 0) {
823       
824       for(i = 0; i < 8; i++) {
825         if(oldnislct[i+4] == '\0' || !isxdigit(oldnislct[i+4]))
826           break;
827       }
828       if (i == 8) {
829         /*
830          * p points at 8 characters of hex digits -
831          * read into a time_t as the seconds since
832          * 1970 that the password was last changed.
833          */
834         got_pass_last_set_time = True;
835       } /* i == 8 */
836     } /* StrnCaseCmp() */
837
838   } /* p == '[' */
839
840   /* Entry is correctly formed. */
841
842
843
844   /* Create the 32 byte representation of the new p16 */
845   if(pwd->smb_passwd != NULL) {
846     for (i = 0; i < 16; i++) {
847       slprintf(&lmpwd[i*2], 32, "%02X", (uchar) pwd->smb_passwd[i]);
848     }
849   } else {
850     if(pwd->acct_ctrl & ACB_PWNOTREQ)
851       fstrcpy(lmpwd, "NO PASSWORDXXXXXXXXXXXXXXXXXXXXX");
852     else
853       fstrcpy(lmpwd, "XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX");
854   }
855
856   /* Add on the NT md4 hash */
857   if (pwd->smb_nt_passwd != NULL) {
858     for (i = 0; i < 16; i++) {
859       slprintf(&ntpwd[i*2], 32, "%02X", (uchar) pwd->smb_nt_passwd[i]);
860     }
861   } else {
862     if(pwd->acct_ctrl & ACB_PWNOTREQ)
863       fstrcpy(ntpwd, "NO PASSWORDXXXXXXXXXXXXXXXXXXXXX");
864     else
865       fstrcpy(ntpwd, "XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX");
866   }
867   
868   pwd->pass_last_set_time = time(NULL);
869
870   if(got_pass_last_set_time) {
871     slprintf(lct, 12, "LCT-%08X", (uint32)pwd->pass_last_set_time);
872   }
873
874   set_single_attribute(obj, NPF_LMPWD,     lmpwd, strlen(lmpwd), EN_CRYPT);
875   set_single_attribute(obj, NPF_NTPWD,     ntpwd, strlen(ntpwd), EN_CRYPT);
876   set_single_attribute(obj, NPF_ACB,       acb,   strlen(acb),   0);
877   set_single_attribute(obj, NPF_PWDLSET_T, lct,   strlen(lct),   0);
878
879   addresult =
880     nis_add_entry(lp_smb_passwd_file(), obj, 
881                   ADD_OVERWRITE | FOLLOW_PATH | EXPAND_NAME | HARD_LOOKUP);
882   
883   if(addresult->status != NIS_SUCCESS) {
884     DEBUG(0, ("mod_nisp21pwd_entry: NIS+ table update failed: %s %s\n", nisname, nis_sperrno(addresult->status)));
885     nis_freeresult(addresult);
886     nis_freeresult(result);
887     return False;
888   }
889     
890   DEBUG(6,("mod_nisp21pwd_entry: password changed\n"));
891
892   nis_freeresult(addresult);
893   nis_freeresult(result);
894   
895   return True;
896 }
897  
898
899 /*************************************************************************
900  Routine to search the nisplus passwd file for an entry matching the username
901  *************************************************************************/
902 static struct sam_passwd *getnisp21pwnam(char *name)
903 {
904         /* Static buffers we will return. */
905         static struct sam_passwd pw_buf;
906         nis_result *result;
907         pstring nisname;
908         BOOL ret;
909
910         if (!*lp_smb_passwd_file())
911         {
912                 DEBUG(0, ("No SMB password file set\n"));
913                 return NULL;
914         }
915
916         DEBUG(10, ("getnisp21pwnam: search by name: %s\n", name));
917         DEBUG(10, ("getnisp21pwnam: using NIS+ table %s\n", lp_smb_passwd_file()));
918
919         slprintf(nisname, sizeof(nisname)-1, "[name=%s],%s", name, lp_smb_passwd_file());
920
921         /* Search the table. */
922         gotalarm = 0;
923         CatchSignal(SIGALRM, SIGNAL_CAST gotalarm_sig);
924         alarm(5);
925
926         result = nis_list(nisname, FOLLOW_PATH | EXPAND_NAME | HARD_LOOKUP, NULL, NULL);
927
928         alarm(0);
929         CatchSignal(SIGALRM, SIGNAL_CAST SIG_DFL);
930
931         if (gotalarm)
932         {
933                 DEBUG(0,("getnisp21pwnam: NIS+ lookup time out\n"));
934                 nis_freeresult(result);
935                 return NULL;
936         }
937
938         ret = make_sam_from_nisresult(&pw_buf, result);
939         nis_freeresult(result);
940
941         return ret ? &pw_buf : NULL;
942 }
943
944 /*************************************************************************
945  Routine to search the nisplus passwd file for an entry matching the username
946  *************************************************************************/
947 static struct sam_passwd *getnisp21pwrid(uint32 rid)
948 {
949         /* Static buffers we will return. */
950         static struct sam_passwd pw_buf;
951         nis_result *result;
952         char *nisname;
953         BOOL ret;
954
955         if (!*lp_smb_passwd_file())
956         {
957                 DEBUG(0, ("getnisp21pwrid: no SMB password file set\n"));
958                 return NULL;
959         }
960
961         DEBUG(10, ("getnisp21pwrid: search by rid: %x\n", rid));
962         DEBUG(10, ("getnisp21pwrid: using NIS+ table %s\n", lp_smb_passwd_file()));
963
964         nisname = make_nisname_from_user_rid(rid, lp_smb_passwd_file());
965
966         /* Search the table. */
967         gotalarm = 0;
968         CatchSignal(SIGALRM, SIGNAL_CAST gotalarm_sig);
969         alarm(5);
970
971         result = nis_list(nisname, FOLLOW_PATH | EXPAND_NAME | HARD_LOOKUP, NULL, NULL);
972
973         alarm(0);
974         CatchSignal(SIGALRM, SIGNAL_CAST SIG_DFL);
975
976         if (gotalarm)
977         {
978                 DEBUG(0,("getnisp21pwrid: NIS+ lookup time out\n"));
979                 nis_freeresult(result);
980                 return NULL;
981         }
982
983         ret = make_sam_from_nisresult(&pw_buf, result);
984         nis_freeresult(result);
985
986         return ret ? &pw_buf : NULL;
987 }
988
989 /*
990  * Derived functions for NIS+.
991  */
992
993 static struct smb_passwd *getnisppwent(void *vp)
994 {
995         return pdb_sam_to_smb(getnisp21pwent(vp));
996 }
997
998 static BOOL add_nisppwd_entry(struct smb_passwd *newpwd)
999 {
1000         return add_nisp21pwd_entry(pdb_smb_to_sam(newpwd));
1001 }
1002
1003 static BOOL mod_nisppwd_entry(struct smb_passwd* pwd, BOOL override)
1004 {
1005         return mod_nisp21pwd_entry(pdb_smb_to_sam(pwd), override);
1006 }
1007
1008 static struct smb_passwd *getnisppwnam(char *name)
1009 {
1010         return pdb_sam_to_smb(getnisp21pwnam(name));
1011 }
1012
1013 static struct sam_passwd *getnisp21pwuid(uid_t smb_userid)
1014 {
1015         return getnisp21pwrid(pdb_uid_to_user_rid(smb_userid));
1016 }
1017
1018 static struct smb_passwd *getnisppwrid(uint32 user_rid)
1019 {
1020         return pdb_sam_to_smb(getnisp21pwuid(pdb_user_rid_to_uid(user_rid)));
1021 }
1022
1023 static struct smb_passwd *getnisppwuid(uid_t smb_userid)
1024 {
1025         return pdb_sam_to_smb(getnisp21pwuid(smb_userid));
1026 }
1027
1028 static struct sam_disp_info *getnispdispnam(char *name)
1029 {
1030         return pdb_sam_to_dispinfo(getnisp21pwnam(name));
1031 }
1032
1033 static struct sam_disp_info *getnispdisprid(uint32 rid)
1034 {
1035         return pdb_sam_to_dispinfo(getnisp21pwrid(rid));
1036 }
1037
1038 static struct sam_disp_info *getnispdispent(void *vp)
1039 {
1040         return pdb_sam_to_dispinfo(getnisp21pwent(vp));
1041 }
1042
1043 static struct passdb_ops nispasswd_ops = {
1044   startnisppwent,
1045   endnisppwent,
1046   getnisppwpos,
1047   setnisppwpos,
1048   getnisppwnam,
1049   getnisppwuid,
1050   getnisppwrid,
1051   getnisppwent,
1052   add_nisppwd_entry,
1053   mod_nisppwd_entry,
1054   getnisp21pwent,
1055   getnisp21pwnam,
1056   getnisp21pwuid,
1057   getnisp21pwrid, 
1058   add_nisp21pwd_entry,
1059   mod_nisp21pwd_entry,
1060   getnispdispnam,
1061   getnispdisprid,
1062   getnispdispent
1063 };
1064
1065 struct passdb_ops *nisplus_initialize_password_db(void)
1066 {
1067   return &nispasswd_ops;
1068 }
1069  
1070 #else
1071  void nisplus_dummy_function(void);
1072  void nisplus_dummy_function(void) { } /* stop some compilers complaining */
1073 #endif /* WITH_NISPLUS */
1074
1075 /* useful code i can't bring myself to delete */
1076 #if 0
1077 static void useful_code(void) {
1078         /* checks user in unix password database.  don't want to do that, here. */
1079         nisname = make_nisname_from_name(newpwd->smb_name, "passwd.org_dir");
1080
1081         nis_user = nis_list(nisname, FOLLOW_PATH | EXPAND_NAME | HARD_LOOKUP, NULL, NULL);
1082
1083         if (nis_user->status != NIS_SUCCESS || NIS_RES_NUMOBJ(nis_user) <= 0)
1084         {
1085                 DEBUG(3, ("useful_code: Unable to get NIS+ passwd entry for user: %s.\n",
1086                         nis_sperrno(nis_user->status)));
1087                 return False;
1088         }
1089
1090         user_obj = NIS_RES_OBJECT(nis_user);
1091         make_nisname_from_name(ENTRY_VAL(user_obj,0), pfile);
1092 }
1093 #endif