a580e12000-09-27Fredrik Hübinette (Hubbe) #pike __REAL_VERSION__
a20af62000-09-26Fredrik Hübinette (Hubbe) 
aa370a1999-04-24Johan Schön // LDAP client protocol implementation for Pike. // // Honza Petrous, hop@unibase.cz // // ---------------------------------------------------------------------- // // History: // // v1.9 1999-02-19 created separate file // - improved checking of readed bytes in 'readmsg' // v1.9.1.1 // 1999-03-21 - changed FILE to File (unbuffered) // - some inactive code // // v1.10 1999-03-28 - rewritten methods 'readmsg' & 'writemsg' // to new method 'xchgmsg' // - added core for async operation //
cec0932005-03-11Martin Stjernholm import Protocols.LDAP;
aa370a1999-04-24Johan Schön #include "ldap_globals.h" // private variables int next_id = 1; // message id counter int ldap_version = LDAP_DEFAULT_VERSION; // actually used protocol vers.
c908692005-04-06Martin Stjernholm  string ldap_rem_errstr = ldap_error_strings[LDAP_SUCCESS]; // last remote error description
aa370a1999-04-24Johan Schön  int ldap_errno = LDAP_SUCCESS; // last error code /*private*/ string readbuf=""; // read buffer private int ok; // read buffer status /*private*/ string writebuf=""; // write buffer // private written; // count of written chars
4b516a2008-01-04Martin Nilsson  private function con_ok; // async callback functions
aa370a1999-04-24Johan Schön  object conthread; // thread connection array extra_args; // not used, yet // /*private*/ int errno; int connected = 0;
4348442014-05-22Martin Nilsson  #if constant(SSL.Cipher)
fc7f092014-06-01Martin Nilsson  Stdio.Stream|SSL.File ldapfd; // helper fd
4348442014-05-22Martin Nilsson #else Stdio.Stream ldapfd; // helper fd #endif
aa370a1999-04-24Johan Schön 
9eaf1d2008-06-28Martin Nilsson protected int last_io_time; // Timestamp when I/O on the fd was made last.
bd564d2005-03-29Martin Stjernholm 
c908692005-04-06Martin Stjernholm  int seterr(int errno, void|string errstr) {
aa370a1999-04-24Johan Schön  // Sets ldap_err* variables and returns errno
c908692005-04-06Martin Stjernholm  ldap_rem_errstr = errstr;
aa370a1999-04-24Johan Schön  ldap_errno = errno;
6659452003-09-01Martin Nilsson  return errno;
aa370a1999-04-24Johan Schön  }
0b5e392002-07-22H. William Welliver III  //!
b3adf32008-10-29Martin Stjernholm  //! Returns the error number from the last transaction. If the error //! is @[LDAP_SERVER_DOWN] then there was a socket error, and the //! I/O error number can be retrieved using //! @expr{@[ldapfd]->errno()@}.
0b5e392002-07-22H. William Welliver III  //! //! @seealso
c908692005-04-06Martin Stjernholm  //! @[error_string], @[server_error_string]
6659452003-09-01Martin Nilsson  int error_number() { return ldap_errno; }
aa370a1999-04-24Johan Schön 
0b5e392002-07-22H. William Welliver III  //!
c908692005-04-06Martin Stjernholm  //! Returns the description of the error from the last transaction. //! This is the error string from the server, or a standard error //! message corresponding to the error number if the server didn't //! provide any description.
0b5e392002-07-22H. William Welliver III  //!
b3adf32008-10-29Martin Stjernholm  //! If @[error_number] returns @[LDAP_SERVER_DOWN] then this is the //! @[strerror] message corresponding to the I/O error for the //! connection. //!
0b5e392002-07-22H. William Welliver III  //! @seealso
c908692005-04-06Martin Stjernholm  //! @[server_error_string], @[error_number] string error_string() { return ldap_rem_errstr || ldap_error_strings[ldap_errno]; } //! Returns the error string from the server, or zero if the server //! didn't provide any. //! //! @seealso //! @[error_string], @[error_number] string server_error_string() {return ldap_rem_errstr;}
aa370a1999-04-24Johan Schön 
6659452003-09-01Martin Nilsson  array error() { return ({error_number(), error_string()}); }
aa370a1999-04-24Johan Schön 
bd564d2005-03-29Martin Stjernholm //! Returns when I/O was made last. Useful to find out whether it's //! safe to continue using a connection that has been idle for some //! time. int get_last_io_time() {return last_io_time;}
9eaf1d2008-06-28Martin Nilsson  protected void read_answer() {
aa370a1999-04-24Johan Schön  // ---------------------- // Reads LDAP PDU (with defined msgid) from the server int msglen = 0, ix, ofs; string s, shlp;
ead9722003-01-20Martin Nilsson  if(sizeof(readbuf) < 2)
0668612001-09-14Honza Petrous  readbuf = ldapfd->read(2); // 1. byte = 0x0C, 2. byte = msglen
ead9722003-01-20Martin Nilsson  if (intp(readbuf) || (sizeof(readbuf) < 2)) {
b3adf32008-10-29Martin Stjernholm  seterr (LDAP_SERVER_DOWN, !readbuf ? strerror (ldapfd->errno()) : "Connection closed"); ERROR ("LDAP read error: %s\n", ldap_rem_errstr);
6659452003-09-01Martin Nilsson  //return -ldap_errno;
aa370a1999-04-24Johan Schön  return; } if (readbuf[0] != '0') { seterr (LDAP_PROTOCOL_ERROR);
8648672004-06-18Henrik Grubbström (Grubba)  DWRITE_HI("protocol.read_answer: ERROR: retv=<"+sprintf("%O",readbuf)+">\n");
aa370a1999-04-24Johan Schön  THROW(({"LDAP: Protocol mismatch.\n",backtrace()}));
6659452003-09-01Martin Nilsson  //return -ldap_errno;
aa370a1999-04-24Johan Schön  return; }
8648672004-06-18Henrik Grubbström (Grubba)  DWRITE(sprintf("protocol.read_answer: sizeof = %d\n", sizeof(readbuf)));
aa370a1999-04-24Johan Schön  msglen = readbuf[1]; ofs = 2; if (msglen & 0x80) { // > 0x7f if (msglen == 0x80) { // RFC not allows unexplicitly defined length seterr (LDAP_PROTOCOL_ERROR); THROW(({"LDAP: Protocol mismatch.\n",backtrace()}));
6659452003-09-01Martin Nilsson  //return -ldap_errno;
aa370a1999-04-24Johan Schön  return; } ofs = (msglen & 0x7f) + 2;
ead9722003-01-20Martin Nilsson  ix = ofs - sizeof(readbuf);
aa370a1999-04-24Johan Schön  if(ix > 0)
0668612001-09-14Honza Petrous  s = ldapfd->read(ix);
ead9722003-01-20Martin Nilsson  if (!s || (sizeof(s) < ix)) {
b3adf32008-10-29Martin Stjernholm  seterr (LDAP_SERVER_DOWN, !s ? strerror (ldapfd->errno()) : "Connection closed"); ERROR ("LDAP read error: %s\n", ldap_rem_errstr);
6659452003-09-01Martin Nilsson  //return -ldap_errno;
aa370a1999-04-24Johan Schön  return; } readbuf += s; msglen = 0; // !!! RESTRICTION: 2^32 !!! shlp = reverse(readbuf[2..ofs]);
ead9722003-01-20Martin Nilsson  for (ix=0; ix<sizeof(shlp); ix++) {
aa370a1999-04-24Johan Schön  msglen += shlp[ix]*(1<<(ix*8)); } }
ead9722003-01-20Martin Nilsson  ix = (ofs + msglen) - sizeof(readbuf);
aa370a1999-04-24Johan Schön  if(ix > 0)
0668612001-09-14Honza Petrous  s = ldapfd->read(ix);
ead9722003-01-20Martin Nilsson  if (!s || (sizeof(s) < ix)) {
b3adf32008-10-29Martin Stjernholm  seterr (LDAP_CONNECT_ERROR, !s ? strerror (ldapfd->errno()) : "Connection closed"); ERROR ("LDAP read error: %s\n", ldap_rem_errstr);
6659452003-09-01Martin Nilsson  //return -ldap_errno;
aa370a1999-04-24Johan Schön  return; } readbuf += s;
3e88822013-08-30Martin Nilsson  //DWRITE(sprintf("protocol.read_answer: %O\n", .ldap_privates.ldap_der_decode(readbuf)));
8648672004-06-18Henrik Grubbström (Grubba)  DWRITE("protocol.read_answer: ok=1.\n");
aa370a1999-04-24Johan Schön  ok = 1;
bd564d2005-03-29Martin Stjernholm  last_io_time = time();
aa370a1999-04-24Johan Schön  if(con_ok)
563bd72004-01-11Martin Nilsson  con_ok(this, @extra_args);
aa370a1999-04-24Johan Schön  }
9eaf1d2008-06-28Martin Nilsson  protected int is_whole_pdu() {
aa370a1999-04-24Johan Schön  // ---------------------- // Check if LDAP PDU is complete in 'readbuf' int msglen, ix, ofs; string shlp;
ead9722003-01-20Martin Nilsson  if (sizeof(readbuf) < 3)
6659452003-09-01Martin Nilsson  return 0; // PDU have min. 3 bytes
aa370a1999-04-24Johan Schön  if (readbuf[0] != '0')
6659452003-09-01Martin Nilsson  return 1; // PDU has bad header -> forced execution
aa370a1999-04-24Johan Schön  msglen = readbuf[1]; if (msglen & 0x80) { // > 0x7f if (msglen == 0x80)
6659452003-09-01Martin Nilsson  return 1; // forced execution
aa370a1999-04-24Johan Schön  ofs = (msglen & 0x7f) + 2;
ead9722003-01-20Martin Nilsson  ix = ofs - sizeof(readbuf);
aa370a1999-04-24Johan Schön  if(ix > 0)
6659452003-09-01Martin Nilsson  return 0; // incomplete PDU
aa370a1999-04-24Johan Schön  msglen = 0; shlp = reverse(readbuf[2..ofs]);
ead9722003-01-20Martin Nilsson  for (ix=0; ix<sizeof(shlp); ix++) {
aa370a1999-04-24Johan Schön  msglen += shlp[ix]*(1<<(ix*8)); } }
ead9722003-01-20Martin Nilsson  ix = (ofs + msglen) - sizeof(readbuf);
aa370a1999-04-24Johan Schön  if(ix > 0)
6659452003-09-01Martin Nilsson  return 0; // incomplete PDU
aa370a1999-04-24Johan Schön 
6659452003-09-01Martin Nilsson  return 1;
aa370a1999-04-24Johan Schön  }
0668612001-09-14Honza Petrous  void create(object fd) { // ------------------- ldapfd = fd;
bd564d2005-03-29Martin Stjernholm  last_io_time = time();
aa370a1999-04-24Johan Schön  }
d83c722004-05-25Henrik Grubbström (Grubba)  string|int do_op(object msgop, object|void controls) {
aa370a1999-04-24Johan Schön  // --------------------------- // Make LDAP PDU envelope for 'msgop', send it and read answer ... object msgval; object msgid; int rv = 0, msgnum; //THREAD_LOCK msgnum = next_id++; //THREAD_UNLOCK msgid = Standards.ASN1.Types.asn1_integer(msgnum);
d83c722004-05-25Henrik Grubbström (Grubba)  if (controls) { msgval = Standards.ASN1.Types.asn1_sequence(({msgid, msgop, controls})); } else { msgval = Standards.ASN1.Types.asn1_sequence(({msgid, msgop})); }
aa370a1999-04-24Johan Schön  if (objectp(msgval)) { DWRITE(sprintf("protocol.do_op: msg = [%d]\n",sizeof(msgval->get_der()))); } else DWRITE("protocol.do_op: msg is null!\n"); // call_out writebuf = msgval->get_der();
0668612001-09-14Honza Petrous  rv = ldapfd->write(writebuf); // !!!!! - jak rozlisit async a sync ????
aa370a1999-04-24Johan Schön  // call_out if (rv < 2) {
b3adf32008-10-29Martin Stjernholm  seterr (LDAP_SERVER_DOWN, strerror (ldapfd->errno())); ERROR ("LDAP write error: %s\n", ldap_rem_errstr);
6659452003-09-01Martin Nilsson  return -ldap_errno;
aa370a1999-04-24Johan Schön  } DWRITE(sprintf("protocol.do_op: write OK [%d bytes].\n",rv)); msgval = 0; msgid = 0; writebuf= ""; readbuf= ""; // !!! NEni to pozde ?
bd564d2005-03-29Martin Stjernholm  last_io_time = time();
aa370a1999-04-24Johan Schön  //`()(); read_answer(); // now is all in 'readbuf'
6659452003-09-01Martin Nilsson  return readbuf;
aa370a1999-04-24Johan Schön  } /* ------------ legacy support -----------------*/ string|int readmsg(int msgid) { // Reads LDAP PDU (with defined msgid) from server, checks msgid ... int msglen = 0, ix;
89cbf81999-12-30Henrik Grubbström (Grubba)  string|int retv;
1498051999-12-30Henrik Grubbström (Grubba)  string s, shlp;
aa370a1999-04-24Johan Schön 
0668612001-09-14Honza Petrous  retv = ldapfd->read(2); // 1. byte = 0x0C, 2. byte = msglen
aa370a1999-04-24Johan Schön  if (!retv || (sizeof(retv) != 2) || (retv[0] != '0')) {
b3adf32008-10-29Martin Stjernholm  seterr (LDAP_SERVER_DOWN, !retv ? strerror (ldapfd->errno()) : "Connection closed"); ERROR ("LDAP read error: %s\n", ldap_rem_errstr);
6659452003-09-01Martin Nilsson  return -ldap_errno;
aa370a1999-04-24Johan Schön  } DWRITE(sprintf("protocol.readmsg: sizeof = %d\n", sizeof(retv))); msglen = retv[1]; if (msglen & 0x80) { // > 0x7f
8648672004-06-18Henrik Grubbström (Grubba)  if (msglen == 0x80) { // RFC does not allow implicitly defined length
aa370a1999-04-24Johan Schön  seterr (LDAP_PROTOCOL_ERROR); THROW(({"LDAP: Protocol mismatch.\n",backtrace()}));
6659452003-09-01Martin Nilsson  return -ldap_errno;
aa370a1999-04-24Johan Schön  }
0668612001-09-14Honza Petrous  s = ldapfd->read(msglen & 0x7f);
aa370a1999-04-24Johan Schön  if (!s) {
b3adf32008-10-29Martin Stjernholm  seterr (LDAP_SERVER_DOWN, strerror (ldapfd->errno())); ERROR ("LDAP read error: %s\n", ldap_rem_errstr);
6659452003-09-01Martin Nilsson  return -ldap_errno;
aa370a1999-04-24Johan Schön  } retv += s; msglen = 0; // !!! RESTRICTION: 2^32 !!! shlp = reverse(s); for (ix=0; ix<sizeof(shlp); ix++) { msglen += shlp[ix]*(1<<(ix*8)); } }
8648672004-06-18Henrik Grubbström (Grubba)  DWRITE(sprintf("protocol.readmsg: reading %d bytes.\n", msglen));
0668612001-09-14Honza Petrous  s = ldapfd->read(msglen);
aa370a1999-04-24Johan Schön  if (!s | (sizeof(s) < msglen)) {
b3adf32008-10-29Martin Stjernholm  seterr (LDAP_SERVER_DOWN, !s ? strerror (ldapfd->errno()) : "Connection closed"); ERROR ("LDAP read error: %s\n", ldap_rem_errstr);
6659452003-09-01Martin Nilsson  return -ldap_errno;
aa370a1999-04-24Johan Schön  } retv += s;
bd564d2005-03-29Martin Stjernholm  last_io_time = time();
3e88822013-08-30Martin Nilsson  DWRITE(sprintf("protocol.readmsg: %O\n", .ldap_privates.ldap_der_decode(retv)));
6659452003-09-01Martin Nilsson  return retv;
aa370a1999-04-24Johan Schön  } int writemsg(object msgop) { // Make LDAP PDU envelope for 'msgop' and send it object msgval; object msgid; int rv = 0, msgnum; //THREAD_LOCK msgnum = next_id++; //THREAD_UNLOCK msgid = Standards.ASN1.Types.asn1_integer(msgnum); msgval = Standards.ASN1.Types.asn1_sequence(({msgid, msgop})); if (objectp(msgval)) { DWRITE(sprintf("protocol.writemsg: msg = [%d]\n",sizeof(msgval->get_der()))); } else DWRITE("protocol.writemsg: msg is null!\n"); // call_out
0668612001-09-14Honza Petrous  rv = ldapfd->write(msgval->get_der());
aa370a1999-04-24Johan Schön  // call_out if (rv < 2) {
b3adf32008-10-29Martin Stjernholm  seterr (LDAP_SERVER_DOWN, strerror (ldapfd->errno())); ERROR ("LDAP write error: %s\n", ldap_rem_errstr);
6659452003-09-01Martin Nilsson  return -ldap_errno;
aa370a1999-04-24Johan Schön  } DWRITE(sprintf("protocol.writemsg: write OK [%d bytes].\n",rv)); msgval = 0; msgid = 0;
bd564d2005-03-29Martin Stjernholm  last_io_time = time();
6659452003-09-01Martin Nilsson  return msgnum;
aa370a1999-04-24Johan Schön  }