Big cleanups, reworked CokeBank API
[tpg/opendispense2.git] / src / cokebank_basic / main.c
1 /*
2  * OpenDispense 2 
3  * UCC (University [of WA] Computer Club) Electronic Accounting System
4  *
5  * cokebank.c - Coke-Bank management
6  * > Simple custom database format (uses PAM for usernames)
7  *
8  * This file is licenced under the 3-clause BSD Licence. See the file COPYING
9  * for full details.
10  */
11 #include <stdlib.h>
12 #include <stdint.h>
13 #include <stdio.h>
14 #include <string.h>
15 #include <string.h>
16 #include <limits.h>
17 #include <pwd.h>
18 #include <grp.h>
19 #include <openssl/sha.h>
20 #include "common.h"
21 #if USE_LDAP
22 # include <ldap.h>
23 #endif
24
25 /*
26  * NOTES:
27  * 
28  * http://linuxdevcenter.com/pub/a/linux/2003/08/14/libldap.html
29  * - Using libldap, the LDAP Client Library 
30  * 
31  */
32
33 #define USE_UNIX_GROUPS 1
34 #define HACK_TPG_NOAUTH 1
35 #define HACK_ROOT_NOAUTH        1
36
37 #define indexof(array, ent)     (((intptr_t)(ent)-(intptr_t)(array))/sizeof((array)[0]))
38
39 // === TYPES ===
40 struct sAcctIterator
41 {
42          int    CurUser;
43          
44          int    Sort;
45          
46          int    MinBalance;
47          int    MaxBalance;
48          
49          int    FlagMask;
50          int    FlagValue;
51 };
52
53 // === PROTOTYPES ===
54 void    Init_Cokebank(const char *Argument);
55 static int Bank_int_ReadDatabase(void);
56 static int Bank_int_WriteEntry(int ID);
57  int    Bank_Transfer(int SourceUser, int DestUser, int Ammount, const char *Reason);
58  int    Bank_CreateUser(const char *Username);
59 tAcctIterator   *Bank_Iterator(int FlagMask, int FlagValues,
60         int Flags, int MinMaxBalance, time_t LastSeen);
61  int    Bank_GetUserID(const char *Username);
62  int    Bank_GetBalance(int User);
63  int    Bank_GetFlags(int User);
64  int    Bank_SetFlags(int User, int Mask, int Value);
65  int    Bank_int_AlterUserBalance(int ID, int Delta);
66  int    Bank_int_GetMinAllowedBalance(int ID);
67  int    Bank_int_AddUser(const char *Username);
68 char    *Bank_GetUserName(int User);
69  int    Bank_int_GetUnixID(const char *Username);
70  int    Bank_GetUserAuth(const char *Salt, const char *Username, const char *Password);
71 #if USE_LDAP
72 char    *ReadLDAPValue(const char *Filter, char *Value);
73 #endif
74 void    HexBin(uint8_t *Dest, int BufSize, const char *Src);
75
76 // === GLOBALS ===
77 FILE    *gBank_LogFile;
78 #if USE_LDAP
79 char    *gsLDAPPath = "ldapi:///";
80 LDAP    *gpLDAP;
81 #endif
82 tUser   *gaBank_Users;
83  int    giBank_NumUsers;
84 FILE    *gBank_File;
85 tUser   **gaBank_UsersByName;
86 tUser   **gaBank_UsersByBalance;
87
88 // === CODE ===
89 /*
90  * \brief Load the cokebank database
91  */
92 void Init_Cokebank(const char *Argument)
93 {
94         #if USE_LDAP
95          int    rv;
96         #endif
97         
98         // Open Cokebank
99         gBank_File = fopen(Argument, "rb+");
100         if( !gBank_File )       gBank_File = fopen(Argument, "wb+");
101         if( !gBank_File )       perror("Opening coke bank");
102         Bank_int_ReadDatabase();
103
104         // Open log file
105         // TODO: Do I need this?
106         gBank_LogFile = fopen("cokebank.log", "a");
107         if( !gBank_LogFile )    gBank_LogFile = stdout;
108         
109         
110         #if USE_LDAP
111         // Connect to LDAP
112         rv = ldap_create(&gpLDAP);
113         if(rv) {
114                 fprintf(stderr, "ldap_create: %s\n", ldap_err2string(rv));
115                 exit(1);
116         }
117         rv = ldap_initialize(&gpLDAP, gsLDAPPath);
118         if(rv) {
119                 fprintf(stderr, "ldap_initialize: %s\n", ldap_err2string(rv));
120                 exit(1);
121         }
122         { int ver = LDAP_VERSION3; ldap_set_option(gpLDAP, LDAP_OPT_PROTOCOL_VERSION, &ver); }
123         # if 0
124         rv = ldap_start_tls_s(gpLDAP, NULL, NULL);
125         if(rv) {
126                 fprintf(stderr, "ldap_start_tls_s: %s\n", ldap_err2string(rv));
127                 exit(1);
128         }
129         # endif
130         {
131                 struct berval   cred;
132                 struct berval   *servcred;
133                 cred.bv_val = "secret";
134                 cred.bv_len = 6;
135                 rv = ldap_sasl_bind_s(gpLDAP, "cn=admin,dc=ucc,dc=gu,dc=uwa,dc=edu,dc=au",
136                         "", &cred, NULL, NULL, &servcred);
137                 if(rv) {
138                         fprintf(stderr, "ldap_start_tls_s: %s\n", ldap_err2string(rv));
139                         exit(1);
140                 }
141         }
142         #endif
143 }
144
145 /**
146  * \brief Name compare function for qsort
147  */
148 static int Bank_int_CompareNames(const void *Ent1, const void *Ent2)
149 {
150         const tUser     *user1 = *(const tUser**)Ent1;
151         const tUser     *user2 = *(const tUser**)Ent2;
152         
153         return strcmp(user1->Name, user2->Name);
154 }
155
156 /**
157  * \brief Name compare function for qsort
158  */
159 static int Bank_int_CompareBalance(const void *Ent1, const void *Ent2)
160 {
161         const tUser     *user1 = *(const tUser**)Ent1;
162         const tUser     *user2 = *(const tUser**)Ent2;
163         
164         return user1->Balance - user2->Balance;
165 }
166
167 #if 1
168 static int Bank_int_ReadDatabase(void)
169 {
170          int    i;
171         if( gaBank_Users )      return 1;
172         
173         // Get size
174         fseek(gBank_File, 0, SEEK_END);
175         giBank_NumUsers = ftell(gBank_File) / sizeof(tFileUser);
176         fseek(gBank_File, 0, SEEK_SET);
177         
178         // Allocate structures
179         gaBank_Users = malloc( giBank_NumUsers * sizeof(tUser) );
180         gaBank_UsersByName = malloc( giBank_NumUsers * sizeof(tUser*) );
181         gaBank_UsersByBalance = malloc( giBank_NumUsers * sizeof(tUser*) );
182         // Read data
183         for( i = 0; i < giBank_NumUsers; i ++ )
184         {
185                 tFileUser       fu;
186                 fread(&fu, sizeof(tFileUser), 1, gBank_File);
187                 gaBank_Users[i].Name = NULL;
188                 gaBank_Users[i].UnixID = fu.UnixID;
189                 gaBank_Users[i].Balance = fu.Balance;
190                 gaBank_Users[i].Flags = fu.Flags;
191                 gaBank_Users[i].Name = Bank_GetUserName(i);
192                 gaBank_UsersByName[i] = &gaBank_Users[i];       // Add to name index
193                 gaBank_UsersByBalance[i] = &gaBank_Users[i];    // Add to balance index
194         }
195         
196         // Sort indexes
197         qsort(gaBank_UsersByName, giBank_NumUsers, sizeof(tUser*), Bank_int_CompareNames);
198         qsort(gaBank_UsersByBalance, giBank_NumUsers, sizeof(tUser*), Bank_int_CompareBalance);
199         
200         return 0;
201 }
202 #else
203 static int Bank_int_ReadDatabase(void)
204 {
205         char    buf[BUFSIZ];
206         // Alternate data format
207         // > Plain Text
208         // <username>,<uid>,<pin>,<lastused>,<balance>,<flags>,<altlogins...>
209         fseek(gBank_File, 0, SEEK_SET);
210         
211         while(1)
212         {
213                 fgets(buf, BUFSIZ-1, gBank_File);
214         }
215 }
216 #endif
217
218 static int Bank_int_WriteEntry(int ID)
219 {
220         tFileUser       fu;
221         if( ID < 0 || ID >= giBank_NumUsers ) {
222                 return -1;
223         }
224         
225         // Commit to file
226         fseek(gBank_File, ID*sizeof(fu), SEEK_SET);
227         
228         fu.UnixID = gaBank_Users[ID].UnixID;
229         fu.Balance = gaBank_Users[ID].Balance;
230         fu.Flags = gaBank_Users[ID].Flags;
231         
232         fwrite(&fu, sizeof(fu), 1, gBank_File);
233         
234         return 0;
235 }
236
237 /*
238  * Transfers money from one user to another
239  * \param SourceUser    Source user
240  * \param DestUser      Destination user
241  * \param Ammount       Ammount of cents to move from \a SourceUser to \a DestUser
242  * \param Reason        Reason for the transfer (essentially a comment)
243  * \return Boolean failure
244  */
245 int Bank_Transfer(int SourceUser, int DestUser, int Ammount, const char *Reason)
246 {
247          int    srcBal = Bank_GetBalance(SourceUser);
248          int    dstBal = Bank_GetBalance(DestUser);
249         
250         if( srcBal - Ammount < Bank_int_GetMinAllowedBalance(SourceUser) )
251                 return 1;
252         if( dstBal + Ammount < Bank_int_GetMinAllowedBalance(DestUser) )
253                 return 1;
254         Bank_int_AlterUserBalance(DestUser, Ammount);
255         Bank_int_AlterUserBalance(SourceUser, -Ammount);
256         fprintf(gBank_LogFile, "Transfer %ic #%i{%i} > #%i{%i} [%i, %i] (%s)\n",
257                 Ammount, SourceUser, srcBal, DestUser, dstBal,
258                 srcBal - Ammount, dstBal + Ammount, Reason);
259         return 0;
260 }
261
262 int Bank_CreateUser(const char *Username)
263 {
264          int    ret;
265         
266         ret = Bank_GetUserID(Username);
267         if( ret != -1 ) return -1;
268         
269         return Bank_int_AddUser(Username);
270 }
271
272 tAcctIterator *Bank_Iterator(int FlagMask, int FlagValues, int Flags, int MinMaxBalance, time_t LastSeen)
273 {
274         tAcctIterator   *ret;
275         
276         ret = calloc( 1, sizeof(tAcctIterator) );
277         if( !ret )
278                 return NULL;
279         ret->MinBalance = INT_MIN;
280         ret->MaxBalance = INT_MAX;
281         
282         ret->FlagMask = FlagMask;
283         ret->FlagValue = FlagValues & FlagMask;
284         
285         if(Flags & BANK_ITFLAG_MINBALANCE)
286                 ret->MinBalance = MinMaxBalance;
287         if(Flags & BANK_ITFLAG_MAXBALANCE)
288                 ret->MaxBalance = MinMaxBalance;
289         
290         ret->Sort = Flags & (BANK_ITFLAG_SORTMASK|BANK_ITFLAG_REVSORT);
291         
292         // Shut up GCC
293         LastSeen = 0;
294         
295         //if(Flags & BANK_ITFLAG_SEENBEFORE)
296         //      ret->MinBalance = MinMaxBalance;
297         //if(Flags & BANK_ITFLAG_SEENAFTER)
298         //      ret->MinBalance = MinMaxBalance;
299         
300         return ret;
301 }
302
303 int Bank_IteratorNext(tAcctIterator *It)
304 {
305          int    ret;
306         
307         while(It->CurUser < giBank_NumUsers)
308         {
309                 switch(It->Sort)
310                 {
311                 case BANK_ITFLAG_SORT_NONE:
312                 case BANK_ITFLAG_SORT_NONE | BANK_ITFLAG_REVSORT:
313                         ret = It->CurUser;
314                         break;
315                 case BANK_ITFLAG_SORT_NAME:
316                         ret = indexof(gaBank_Users, gaBank_UsersByName[It->CurUser]);
317                         break;
318                 case BANK_ITFLAG_SORT_NAME | BANK_ITFLAG_REVSORT:
319                         ret = indexof(gaBank_Users, gaBank_UsersByName[giBank_NumUsers-It->CurUser]);
320                         break;
321                 case BANK_ITFLAG_SORT_BAL:
322                         ret = indexof(gaBank_Users, gaBank_UsersByBalance[It->CurUser]);
323                         printf("Sort by balance (ret = %i)\n", ret);
324                         break;
325                 case BANK_ITFLAG_SORT_BAL | BANK_ITFLAG_REVSORT:
326                         ret = indexof(gaBank_Users, gaBank_UsersByBalance[giBank_NumUsers-It->CurUser]);
327                         break;
328                 default:
329                         fprintf(stderr, "BUG: Unsupported sort in Bank_IteratorNext\n");
330                         return -1;
331                 }
332                 It->CurUser ++;
333                 
334                 if( gaBank_Users[ret].Balance < It->MinBalance )
335                         continue;
336                 if( gaBank_Users[ret].Balance > It->MaxBalance )
337                         continue;
338                 if( (gaBank_Users[ret].Flags & It->FlagMask) != It->FlagValue )
339                         continue;
340                 
341                 return ret;
342         }
343         return -1;
344 }
345
346 void Bank_DelIterator(tAcctIterator *It)
347 {
348         free(It);
349 }
350
351 /*
352  * \brief Get the User ID of the named user
353  */
354 int Bank_GetUserID(const char *Username)
355 {       
356         #if 0
357          int    i, size;
358         i = giBank_NumUsers / 2;
359         size = giBank_NumUsers;
360         for(;;)
361         {
362                 cmp = strcmp(gaBank_UsersByName[i]->Name, Username);
363                 if( cmp == 0 )
364                         return indexof(gaBank_Users, gaBank_UsersByName[i];
365                 
366                 // Not found
367                 if( size == 0 )
368                         return -1;
369                 
370                 if( cmp < 0 )
371                         i += size;
372                 else
373                         i -= size;
374                 size /= 2;
375         }
376         #else
377          int    i, uid;
378         uid = Bank_int_GetUnixID(Username);
379         
380         // Expensive search :(
381         for( i = 0; i < giBank_NumUsers; i ++ )
382         {
383                 if( gaBank_Users[i].UnixID == uid )
384                         return i;
385         }
386         #endif
387
388         return -1;
389 }
390
391 int Bank_GetBalance(int ID)
392 {
393         if( ID < 0 || ID >= giBank_NumUsers )
394                 return INT_MIN;
395
396         return gaBank_Users[ID].Balance;
397 }
398
399 int Bank_GetFlags(int ID)
400 {
401         if( ID < 0 || ID >= giBank_NumUsers )
402                 return -1;
403
404         // root
405         if( gaBank_Users[ID].UnixID == 0 ) {
406                 gaBank_Users[ID].Flags |= USER_FLAG_WHEEL|USER_FLAG_COKE;
407         }
408
409         #if USE_UNIX_GROUPS
410         // TODO: Implement checking the PAM groups and status instead, then
411         // fall back on the database. (and update if there is a difference)
412         if( gaBank_Users[ID].UnixID > 0 )
413         {
414                 struct passwd   *pwd;
415                 struct group    *grp;
416                  int    i;
417                 
418                 // Get username
419                 pwd = getpwuid( gaBank_Users[ID].UnixID );
420                 
421                 // Check for additions to the "coke" group
422                 grp = getgrnam("coke");
423                 if( grp ) {
424                         for( i = 0; grp->gr_mem[i]; i ++ )
425                         {
426                                 if( strcmp(grp->gr_mem[i], pwd->pw_name) == 0 ) {
427                                         gaBank_Users[ID].Flags |= USER_FLAG_COKE;
428                                         break ;
429                                 }
430                         }
431                 }
432                 
433                 // Check for additions to the "wheel" group
434                 grp = getgrnam("wheel");
435                 if( grp ) {
436                         for( i = 0; grp->gr_mem[i]; i ++ )
437                         {
438                                 if( strcmp(grp->gr_mem[i], pwd->pw_name) == 0 ) {
439                                         gaBank_Users[ID].Flags |= USER_FLAG_WHEEL;
440                                         break ;
441                                 }
442                         }
443                 }
444         }
445         #endif
446
447         return gaBank_Users[ID].Flags;
448 }
449
450 int Bank_SetFlags(int ID, int Mask, int Value)
451 {
452         // Sanity
453         if( ID < 0 || ID >= giBank_NumUsers )
454                 return -1;
455         
456         // Silently ignore changes to root and meta accounts
457         if( gaBank_Users[ID].UnixID <= 0 )      return 0;
458         
459         gaBank_Users[ID].Flags &= ~Mask;
460         gaBank_Users[ID].Flags |= Value;
461
462         Bank_int_WriteEntry(ID);
463         
464         return 0;
465 }
466
467 int Bank_int_AlterUserBalance(int ID, int Delta)
468 {
469         // Sanity
470         if( ID < 0 || ID >= giBank_NumUsers )
471                 return -1;
472
473         // Update
474         gaBank_Users[ID].Balance += Delta;
475
476         Bank_int_WriteEntry(ID);
477         
478         return 0;
479 }
480
481 int Bank_int_GetMinAllowedBalance(int ID)
482 {
483          int    flags;
484         if( ID < 0 || ID >= giBank_NumUsers )
485                 return 0;
486
487         flags = Bank_GetFlags(ID);
488
489         // Internal accounts have no limit
490         if( (flags & USER_FLAG_INTERNAL) )
491                 return INT_MIN;
492
493         // Wheel is allowed to go to -$100
494         if( (flags & USER_FLAG_WHEEL) )
495                 return -10000;
496         
497         // Coke is allowed to go to -$20
498         if( (flags & USER_FLAG_COKE) )
499                 return -2000;
500
501         // For everyone else, no negative
502         return 0;
503 }
504
505 /*
506  * Create a new user in our database
507  */
508 int Bank_int_AddUser(const char *Username)
509 {
510         void    *tmp;
511          int    uid = Bank_int_GetUnixID(Username);
512
513         // Can has moar space plz?
514         // - Structures
515         tmp = realloc(gaBank_Users, (giBank_NumUsers+1)*sizeof(gaBank_Users[0]));
516         if( !tmp )      return -1;
517         gaBank_Users = tmp;
518         // - Name index
519         tmp = realloc(gaBank_UsersByName, (giBank_NumUsers+1)*sizeof(tUser*));
520         if( !tmp )      return -1;
521         gaBank_UsersByName = tmp;
522         // - Balance index
523         tmp = realloc(gaBank_UsersByBalance, (giBank_NumUsers+1)*sizeof(tUser*));
524         if( !tmp )      return -1;
525         gaBank_UsersByBalance = tmp;
526
527         // Crete new user
528         gaBank_Users[giBank_NumUsers].Name = NULL;
529         gaBank_Users[giBank_NumUsers].UnixID = uid;
530         gaBank_Users[giBank_NumUsers].Balance = 0;
531         gaBank_Users[giBank_NumUsers].Flags = 0;
532         gaBank_UsersByName[giBank_NumUsers] = &gaBank_Users[giBank_NumUsers];
533         gaBank_UsersByBalance[giBank_NumUsers] = &gaBank_Users[giBank_NumUsers];
534         
535         // Set default flags
536         if( strcmp(Username, COKEBANK_DEBT_ACCT) == 0 ) {
537                 gaBank_Users[giBank_NumUsers].Flags = USER_FLAG_INTERNAL;
538         }
539         else if( strcmp(Username, COKEBANK_SALES_ACCT) == 0 ) {
540                 gaBank_Users[giBank_NumUsers].Flags = USER_FLAG_INTERNAL;
541         }
542         else if( strcmp(Username, "root") == 0 ) {
543                 gaBank_Users[giBank_NumUsers].Flags = USER_FLAG_WHEEL|USER_FLAG_COKE;
544         }
545
546         // Increment count
547         giBank_NumUsers ++;
548         
549         // Get name
550         gaBank_Users[giBank_NumUsers-1].Name = Bank_GetUserName(giBank_NumUsers-1);
551         
552         // Update indexes
553         qsort(gaBank_UsersByName, giBank_NumUsers, sizeof(tUser*), Bank_int_CompareNames);
554         qsort(gaBank_UsersByBalance, giBank_NumUsers, sizeof(tUser*), Bank_int_CompareBalance);
555         
556         // Save
557         Bank_int_WriteEntry(giBank_NumUsers - 1);
558
559         return 0;
560 }
561
562 // ---
563 // Unix user dependent code
564 // TODO: Modify to keep its own list of usernames
565 // ---
566 char *Bank_GetUserName(int ID)
567 {
568         struct passwd   *pwd;
569         
570         if( ID < 0 || ID >= giBank_NumUsers )
571                 return NULL;
572         
573         if( gaBank_Users[ID].Name ) {
574                 return strdup(gaBank_Users[ID].Name);
575         }
576         
577         if( gaBank_Users[ID].UnixID == -1 )
578                 return strdup(COKEBANK_SALES_ACCT);
579
580         if( gaBank_Users[ID].UnixID == -2 )
581                 return strdup(COKEBANK_DEBT_ACCT);
582
583         pwd = getpwuid(gaBank_Users[ID].UnixID);
584         if( !pwd )      return NULL;
585
586         return strdup(pwd->pw_name);
587 }
588
589 int Bank_int_GetUnixID(const char *Username)
590 {
591          int    uid;
592
593         if( strcmp(Username, COKEBANK_SALES_ACCT) == 0 ) {      // Pseudo account that sales are made into
594                 uid = -1;
595         }
596         else if( strcmp(Username, COKEBANK_DEBT_ACCT) == 0 ) {  // Pseudo acount that money is added from
597                 uid = -2;
598         }
599         else {
600                 struct passwd   *pwd;
601                 // Get user ID
602                 pwd = getpwnam(Username);
603                 if( !pwd )      return -1;
604                 uid = pwd->pw_uid;
605         }
606         return uid;
607 }
608
609
610 /*
611  * Authenticate a user
612  */
613 int Bank_GetUserAuth(const char *Salt, const char *Username, const char *Password)
614 {
615         #if USE_LDAP
616         uint8_t hash[20];
617         uint8_t h[20];
618          int    ofs = strlen(Username) + strlen(Salt);
619         char    input[ ofs + 40 + 1];
620         char    tmp[4 + strlen(Username) + 1];  // uid=%s
621         char    *passhash;
622         #endif
623         
624         #if 1
625         // Only here to shut GCC up (until password auth is implemented)
626         if( Salt == NULL )
627                 return -1;
628         if( Password == NULL )
629                 return -1;
630         #endif
631         
632         #if HACK_TPG_NOAUTH
633         if( strcmp(Username, "tpg") == 0 )
634                 return Bank_GetUserID("tpg");
635         #endif
636         #if HACK_ROOT_NOAUTH
637         if( strcmp(Username, "root") == 0 ) {
638                 int ret = Bank_GetUserID("root");
639                 if( ret == -1 )
640                         return Bank_CreateUser("root");
641                 return ret;
642         }
643         #endif
644         
645         #if USE_LDAP
646         HexBin(hash, 20, Password);
647         
648         // Build string to hash
649         strcpy(input, Username);
650         strcpy(input, Salt);
651         
652         // TODO: Get user's SHA-1 hash
653         sprintf(tmp, "uid=%s", Username);
654         printf("tmp = '%s'\n", tmp);
655         passhash = ReadLDAPValue(tmp, "userPassword");
656         if( !passhash ) {
657                 return -1;
658         }
659         printf("LDAP hash '%s'\n", passhash);
660         
661         sprintf(input+ofs, "%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x",
662                 h[ 0], h[ 1], h[ 2], h[ 3], h[ 4], h[ 5], h[ 6], h[ 7], h[ 8], h[ 9],
663                 h[10], h[11], h[12], h[13], h[14], h[15], h[16], h[17], h[18], h[19]
664                 );
665         // Then create the hash from the provided salt
666         // Compare that with the provided hash
667
668         # if 1
669         {
670                  int    i;
671                 printf("Password hash ");
672                 for(i=0;i<20;i++)
673                         printf("%02x", hash[i]&0xFF);
674                 printf("\n");
675         }
676         # endif
677         
678         #endif
679         
680         return -1;
681 }
682
683 #if USE_LDAP
684 char *ReadLDAPValue(const char *Filter, char *Value)
685 {
686         LDAPMessage     *res, *res2;
687         struct berval **attrValues;
688         char    *attrNames[] = {Value,NULL};
689         char    *ret;
690         struct timeval  timeout;
691          int    rv;
692         
693         timeout.tv_sec = 5;
694         timeout.tv_usec = 0;
695         
696         rv = ldap_search_ext_s(gpLDAP, "", LDAP_SCOPE_BASE, Filter,
697                 attrNames, 0, NULL, NULL, &timeout, 1, &res
698                 );
699         printf("ReadLDAPValue: rv = %i\n", rv);
700         if(rv) {
701                 fprintf(stderr, "LDAP Error reading '%s' with filter '%s'\n%s\n",
702                         Value, Filter,
703                         ldap_err2string(rv)
704                         );
705                 return NULL;
706         }
707         
708         res2 = ldap_first_entry(gpLDAP, res);
709         attrValues = ldap_get_values_len(gpLDAP, res2, Value);
710         
711         ret = strndup(attrValues[0]->bv_val, attrValues[0]->bv_len);
712         
713         ldap_value_free_len(attrValues);
714         
715         
716         return ret;
717 }
718 #endif
719
720 // TODO: Move to another file
721 void HexBin(uint8_t *Dest, int BufSize, const char *Src)
722 {
723          int    i;
724         for( i = 0; i < BufSize; i ++ )
725         {
726                 uint8_t val = 0;
727                 
728                 if('0' <= *Src && *Src <= '9')
729                         val |= (*Src-'0') << 4;
730                 else if('A' <= *Src && *Src <= 'F')
731                         val |= (*Src-'A'+10) << 4;
732                 else if('a' <= *Src && *Src <= 'f')
733                         val |= (*Src-'a'+10) << 4;
734                 else
735                         break;
736                 Src ++;
737                 
738                 if('0' <= *Src && *Src <= '9')
739                         val |= (*Src-'0');
740                 else if('A' <= *Src && *Src <= 'F')
741                         val |= (*Src-'A'+10);
742                 else if('a' <= *Src && *Src <= 'f')
743                         val |= (*Src-'a'+10);
744                 else
745                         break;
746                 Src ++;
747                 
748                 Dest[i] = val;
749         }
750         for( ; i < BufSize; i++ )
751                 Dest[i] = 0;
752 }
753

UCC git Repository :: git.ucc.asn.au