1 /* rewrite of the IMAP code by Neil Spring
2 * (nspring@cs.washington.edu) to support gnutls and
3 * persistent connections to servers. */
5 /* Originally written by Yong-iL Joh (tolkien@mizi.com),
6 * modified by Jorge Garcia (Jorge.Garcia@uv.es), and
7 * modified by Jay Francis (jtf@u880.org) to support
17 #include "passwordMgr.h"
19 #include "MessageList.h"
21 #include <sys/types.h>
34 #define PCU (pc->u).pop_imap
38 #define IMAP_DM(pc, lvl, args...) DM(pc, lvl, "imap4: " args)
41 #define DEFROB(x) memfrob(x, x ## _len)
42 #define ENFROB(x) memfrob(x, x ## _len)
48 /* this array maps server:port pairs to file descriptors, so
49 that when more than one mailbox is queried from a server,
50 we only use one socket. It's limited in size by the
51 number of different mailboxes displayed. */
53 static struct fdmap_struct
{
54 char *user_server_port
; /* tuple, in string form */
55 /*@owned@ */ struct connection_state
*cs
;
58 static void ask_user_for_password( /*@notnull@ */ Pop3
*pc
,
61 /* authentication callbacks */
63 static int authenticate_md5( /*@notnull@ */ Pop3
*pc
,
64 struct connection_state
*scs
,
65 const char *capabilities
);
67 static int authenticate_plaintext( /*@notnull@ */ Pop3
*pc
,
68 struct connection_state
*scs
,
69 const char *capabilities
);
71 /* the auth_methods array maps authentication identifiers
72 to the callback that will attempt to authenticate */
73 static struct imap_authentication_method
{
75 /* callback returns 1 if successful, 0 if failed */
76 int (*auth_callback
) ( /*@notnull@ */ Pop3
*pc
,
77 struct connection_state
* scs
,
78 const char *capabilities
);
82 "cram-md5", authenticate_md5
}, {
84 "plaintext", authenticate_plaintext
}, {
89 /* recover a socket from the connection cache */
92 static struct connection_state
*state_for_pcu(Pop3
*pc
)
95 struct connection_state
*retval
= NULL
;
98 malloc(strlen(PCU
.userName
) + strlen(PCU
.serverName
) + 22);
99 sprintf(connection_id
, "%s|%s|%d", PCU
.userName
, PCU
.serverName
,
101 for (i
= 0; i
< FDMAP_SIZE
; i
++)
102 if (fdmap
[i
].user_server_port
!= NULL
&&
103 (strcmp(connection_id
, fdmap
[i
].user_server_port
) == 0)) {
104 retval
= fdmap
[i
].cs
;
110 /* bind to the connection cache */
111 static void bind_state_to_pcu(Pop3
*pc
,
112 /*@owned@ */ struct connection_state
*scs
)
120 malloc(strlen(PCU
.userName
) + strlen(PCU
.serverName
) + 22);
121 sprintf(connection_id
, "%s|%s|%d", PCU
.userName
, PCU
.serverName
,
123 for (i
= 0; i
< FDMAP_SIZE
&& fdmap
[i
].cs
!= NULL
; i
++);
124 if (i
== FDMAP_SIZE
) {
125 /* should never happen */
126 IMAP_DM(pc
, DEBUG_ERROR
,
127 "Tried to open too many IMAP connections. Sorry!\n");
130 fdmap
[i
].user_server_port
= connection_id
;
134 /* remove from the connection cache */
138 struct connection_state
*unbind(
139 /*@returned@*/ struct connection_state
143 struct connection_state
*retval
= NULL
;
146 for (i
= 0; i
< FDMAP_SIZE
&& fdmap
[i
].cs
!= scs
; i
++);
147 if (i
< FDMAP_SIZE
) {
148 free(fdmap
[i
].user_server_port
);
149 fdmap
[i
].user_server_port
= NULL
;
150 retval
= fdmap
[i
].cs
;
156 /* creates a connection to the server, if a matching one doesn't exist. */
157 /* *always* returns null, just declared this wasy to match other protocols. */
159 FILE *imap_open(Pop3
*pc
)
161 static int complained_already
; /* we have to succeed once before
162 complaining again about failure */
163 struct connection_state
*scs
;
164 struct imap_authentication_method
*a
;
165 char *connection_name
;
167 char capabilities
[BUF_SIZE
];
171 if (state_for_pcu(pc
) != NULL
) {
172 /* don't need to open. */
176 /* got this far; we're going to create a connection_state
177 structure, although it might be a blacklist entry */
178 connection_name
= malloc(strlen(PCU
.serverName
) + 20);
179 sprintf(connection_name
, "%s:%d", PCU
.serverName
, PCU
.serverPort
);
183 /* no cached connection */
184 sd
= sock_connect((const char *) PCU
.serverName
, PCU
.serverPort
);
186 if (complained_already
== 0) {
187 IMAP_DM(pc
, DEBUG_ERROR
, "Couldn't connect to %s:%d: %s\n",
188 PCU
.serverName
, PCU
.serverPort
,
189 errno
? strerror(errno
) : "");
190 complained_already
= 1;
192 if (errno
== ETIMEDOUT
) {
193 /* temporarily bump the interval, in a crude way:
194 fast forward time so that the mailbox isn't
195 checked for a while. */
196 pc
->prevtime
= time(0) + 60 * 5; /* now + 60 seconds per min * 5 minutes */
197 /* TCP's retry (how much time has elapsed while
198 the connect times out) is around 3 minutes;
199 here we just try to allow checking local
200 mailboxes more often while remote things are
201 unavailable or disconnected. */
203 free(connection_name
);
207 /* build the connection using STARTTLS */
208 if (PCU
.dossl
!= 0 && (PCU
.serverPort
== 143)) {
209 /* setup an unencrypted binding long enough to invoke STARTTLS */
210 scs
= initialize_unencrypted(sd
, connection_name
, pc
);
213 tlscomm_printf(scs
, "a000 CAPABILITY\r\n");
214 if (tlscomm_expect(scs
, "* CAPABILITY", capabilities
, BUF_SIZE
) ==
216 goto communication_failure
;
218 if (!strstr(capabilities
, "STARTTLS")) {
219 IMAP_DM(pc
, DEBUG_ERROR
,
220 "server doesn't support ssl imap on port 143.");
221 goto communication_failure
;
225 IMAP_DM(pc
, DEBUG_INFO
, "Negotiating TLS within IMAP");
226 tlscomm_printf(scs
, "a001 STARTTLS\r\n");
228 if (tlscomm_expect(scs
, "a001 ", buf
, BUF_SIZE
) == 0)
229 goto communication_failure
;
231 if (strstr(buf
, "a001 OK") == 0) {
232 /* we didn't see the success message in the response */
233 IMAP_DM(pc
, DEBUG_ERROR
, "couldn't negotiate tls. :(\n");
234 goto communication_failure
;
237 /* we don't need the unencrypted state anymore */
238 /* note that communication_failure will close the
239 socket and free via tls_close() */
240 free(scs
); /* fall through will scs = initialize_gnutls(sd); */
243 /* either we've negotiated ssl from starttls, or
244 we're starting an encrypted connection now */
245 if (PCU
.dossl
!= 0) {
246 scs
= initialize_gnutls(sd
, connection_name
, pc
, PCU
.serverName
);
248 IMAP_DM(pc
, DEBUG_ERROR
, "Failed to initialize TLS\n");
252 scs
= initialize_unencrypted(sd
, connection_name
, pc
);
255 /* authenticate; first find out how */
256 /* note that capabilities may have changed since last
257 time we may have asked, if we called STARTTLS, my
258 server will allow plain password login within an
259 encrypted session. */
260 tlscomm_printf(scs
, "a000 CAPABILITY\r\n");
261 if (tlscomm_expect(scs
, "* CAPABILITY", capabilities
, BUF_SIZE
) == 0) {
262 IMAP_DM(pc
, DEBUG_ERROR
, "unable to query capability string\n");
263 goto communication_failure
;
266 /* try each authentication method in turn. */
267 for (a
= auth_methods
; a
->name
!= NULL
; a
++) {
268 /* was it specified or did the user leave it up to us? */
269 if (PCU
.authList
[0] == '\0'
270 || strstr(PCU
.authList
, a
->name
) != NULL
)
271 /* try the authentication method */
272 if ((a
->auth_callback(pc
, scs
, capabilities
)) != 0) {
273 /* store this well setup connection in the cache */
274 bind_state_to_pcu(pc
, scs
);
275 complained_already
= 0;
280 /* if authentication worked, we won't get here */
281 IMAP_DM(pc
, DEBUG_ERROR
,
282 "All authentication methods failed for '%s@%s:%d'\n",
283 PCU
.userName
, PCU
.serverName
, PCU
.serverPort
);
284 communication_failure
:
285 tlscomm_printf(scs
, "a002 LOGOUT\r\n");
291 void imap_cacheHeaders( /*@notnull@ */ Pop3
*pc
);
293 int imap_checkmail( /*@notnull@ */ Pop3
*pc
)
295 /* recover connection state from the cache */
296 struct connection_state
*scs
= state_for_pcu(pc
);
298 char examine_expect
[BUF_SIZE
];
299 static int command_id
;
301 /* if it's not in the cache, try to open */
303 IMAP_DM(pc
, DEBUG_INFO
, "Need new connection to %s@%s\n",
304 PCU
.userName
, PCU
.serverName
);
305 (void) imap_open(pc
);
306 scs
= state_for_pcu(pc
);
312 if (tlscomm_is_blacklisted(scs
) != 0) {
313 /* unresponsive server, don't bother. */
318 tlscomm_printf(scs
, "a%03d EXAMINE %s\r\n", command_id
, pc
->path
);
319 snprintf(examine_expect
, BUF_SIZE
, "a%03d OK", command_id
);
320 if (tlscomm_expect(scs
, examine_expect
, buf
, 127) == 0) {
321 tlscomm_close(unbind(scs
));
326 tlscomm_printf(scs
, "a%03d CLOSE\r\n", command_id
);
327 snprintf(examine_expect
, BUF_SIZE
, "a%03d OK", command_id
);
328 if (tlscomm_expect(scs
, examine_expect
, buf
, 127) == 0) {
329 tlscomm_close(unbind(scs
));
333 /* if we've got it by now, try the status query */
335 tlscomm_printf(scs
, "a%03d STATUS %s (MESSAGES UNSEEN)\r\n",
336 command_id
% 1000, pc
->path
);
337 if (tlscomm_expect(scs
, "* STATUS", buf
, 127) != 0) {
338 /* a valid response? */
339 // doesn't support spaces: (void) sscanf(buf, "* STATUS %*s (MESSAGES %d UNSEEN %d)",
341 msg
= strstr(buf
, "(MESSAGES");
343 (void) sscanf(msg
, "(MESSAGES %d UNSEEN %d)",
344 &(pc
->TotalMsgs
), &(pc
->UnreadMsgs
));
345 /* update the cached headers if evidence that change
346 has occurred; not necessarily complete. */
347 if (pc
->UnreadMsgs
!= pc
->OldUnreadMsgs
||
348 pc
->TotalMsgs
!= pc
->OldMsgs
) {
349 if (PCU
.wantCacheHeaders
) {
350 imap_cacheHeaders(pc
);
354 /* something went wrong. bail. */
355 tlscomm_close(unbind(scs
));
362 imap_releaseHeaders(Pop3
*pc
__attribute__((unused
)), struct msglst
*h
)
365 /* allow the list to be released next time around */
366 if (h
->in_use
<= 0) {
367 /* free the old one */
369 struct msglst
*n
= h
->next
;
378 void imap_cacheHeaders( /*@notnull@ */ Pop3
*pc
)
380 struct connection_state
*scs
= state_for_pcu(pc
);
385 (void) imap_open(pc
);
386 scs
= state_for_pcu(pc
);
391 if (tlscomm_is_blacklisted(scs
) != 0) {
395 if (pc
->headerCache
!= NULL
) {
396 /* decrement the reference count, and free our version */
397 imap_releaseHeaders(pc
, pc
->headerCache
);
398 pc
->headerCache
= NULL
;
401 IMAP_DM(pc
, DEBUG_INFO
, "working headers\n");
403 tlscomm_printf(scs
, "a004 EXAMINE %s\r\n", pc
->path
);
404 if (tlscomm_expect(scs
, "a004 OK", buf
, 127) == 0) {
405 tlscomm_close(unbind(scs
));
408 IMAP_DM(pc
, DEBUG_INFO
, "examine ok\n");
410 /* if we've got it by now, try the status query */
411 tlscomm_printf(scs
, "a005 SEARCH UNSEEN\r\n");
412 if (tlscomm_expect(scs
, "* SEARCH", buf
, 127) == 0) {
413 tlscomm_close(unbind(scs
));
416 IMAP_DM(pc
, DEBUG_INFO
, "search: %s", buf
);
418 return; /* search turned up nothing */
419 msgid
= strtok(buf
+ 9, " \r\n");
420 pc
->headerCache
= NULL
;
421 /* the isdigit cruft is to deal with EOL */
422 if (msgid
!= NULL
&& isdigit(msgid
[0]))
424 struct msglst
*m
= malloc(sizeof(struct msglst
));
426 int fetch_command_done
= FALSE
;
427 tlscomm_printf(scs
, "a04 FETCH %s (FLAGS "
428 "BODY[HEADER.FIELDS (FROM SUBJECT)])\r\n",
430 if (tlscomm_expect(scs
, "* ", hdrbuf
, 127)) {
433 while (m
->subj
[0] == '\0' || m
->from
[0] == '\0') {
434 if (tlscomm_expect(scs
, "", hdrbuf
, 127)) {
435 if (strncasecmp(hdrbuf
, "Subject:", 8) == 0) {
436 strncpy(m
->subj
, hdrbuf
+ 9, SUBJ_LEN
- 1);
437 m
->subj
[SUBJ_LEN
- 1] = '\0';
438 } else if (strncasecmp(hdrbuf
, "From: ", 5) == 0) {
439 strncpy(m
->from
, hdrbuf
+ 6, FROM_LEN
- 1);
440 m
->from
[FROM_LEN
- 1] = '\0';
441 } else if (strncasecmp
442 (hdrbuf
, "a04 OK FETCH", 5) == 0) {
443 /* server says we're done getting this header, which
444 may occur if the message has no subject */
445 if (m
->from
[0] == '\0') {
446 strcpy(m
->from
, " ");
448 if (m
->subj
[0] == '\0') {
449 strcpy(m
->subj
, "(no subject)");
451 fetch_command_done
= TRUE
;
454 IMAP_DM(pc
, DEBUG_ERROR
,
455 "timedout looking for headers.: %s",
457 strcpy(m
->from
, "wmbiff");
458 strcpy(m
->subj
, "failure");
461 IMAP_DM(pc
, DEBUG_INFO
, "From: '%s' Subj: '%s'\n",
463 m
->next
= pc
->headerCache
;
465 pc
->headerCache
->in_use
= 0; /* initialize that it isn't locked */
468 IMAP_DM(pc
, DEBUG_ERROR
, "error fetching: %s", hdrbuf
);
470 if (!fetch_command_done
) {
471 tlscomm_expect(scs
, "a04 OK", hdrbuf
, 127);
474 while ((msgid
= strtok(NULL
, " \r\n")) != NULL
475 && isdigit(msgid
[0]));
477 tlscomm_printf(scs
, "a06 CLOSE\r\n"); /* return to polling state */
478 /* may be unneeded tlscomm_expect(scs, "a06 OK CLOSE\r\n" ); see if it worked? */
479 IMAP_DM(pc
, DEBUG_INFO
, "worked headers\n");
482 /* a client is asking for the headers, hand em a reference, increase the
483 one-bit reference counter */
484 struct msglst
*imap_getHeaders( /*@notnull@ */ Pop3
*pc
)
486 if (pc
->headerCache
== NULL
)
487 imap_cacheHeaders(pc
);
488 if (pc
->headerCache
!= NULL
)
489 pc
->headerCache
->in_use
= 1;
490 return pc
->headerCache
;
493 /* parse the config line to setup the Pop3 structure */
494 int imap4Create( /*@notnull@ */ Pop3
*pc
, const char *const str
)
498 /* special characters aren't allowed in hostnames, rfc 1034 */
499 const char *regexes
[] = {
500 // type : username : password @ hostname (/ name)?(:port)?
501 ".*imaps?:([^: ]{1,255}):([^@]{0,32})@([A-Za-z1-9][-A-Za-z0-9_.]+)(/(\"[^\"]+\")|([^:@ ]+))?(:[0-9]+)?( *([CcAaPp][-A-Za-z5 ]*))?$",
502 ".*imaps?:([^: ]{1,255}) ([^ ]{1,32}) ([A-Za-z1-9][-A-Za-z0-9_.]+)(/(\"[^\"]+\")|([^: ]+))?( [0-9]+)?( *([CcAaPp][-A-Za-z5 ]*))?$",
507 * regulo_atoi expects a pointer-to-int and pop_imap.serverPort is a
508 * uint16_t, so &pop_imap.serverPort is not compatible and we need to use an
509 * int temporary variable to avoid endianness problems.
513 struct regulo regulos
[] = {
514 {1, PCU
.userName
, regulo_strcpy
},
515 {2, PCU
.password
, regulo_strcpy
},
516 {3, PCU
.serverName
, regulo_strcpy
},
517 {4, pc
->path
, regulo_strcpy_skip1
},
518 {7, &serverPort
, regulo_atoi
},
519 {9, PCU
.authList
, regulo_strcpy_tolower
},
525 ".*imaps?:([^: ]{1,256}):([^@]{0,32})@([^/: ]+)(/(\"[^\"]+\")|([^:@ ]+))?(:[0-9]+)?( *(.*))?$";
527 ".*imaps?:([^: ]{1,256}) ([^ ]{1,32}) ([^/: ]+)(/(\"[^\"]+\")|([^: ]+))?( [0-9]+)?( *(.*))?$";
531 /* IMAP4 format: imap:user:password@server/mailbox[:port] */
532 /* If 'str' line is badly formatted, wmbiff won't display the mailbox. */
533 if (strncmp("sslimap:", str
, 8) == 0 || strncmp("imaps:", str
, 6) == 0) {
537 printf("This copy of wmbiff was not compiled with gnutls;\n"
538 "imaps is unavailable. Exiting to protect your\n"
539 "passwords and privacy.\n");
547 serverPort
= (PCU
.dossl
!= 0) ? 993 : 143;
548 PCU
.authList
[0] = '\0';
550 /* argh, str and pc->path are aliases, so we can't just write the default
551 value into the string we're about to parse. */
552 unaliased_str
= strdup(str
);
553 strcpy(pc
->path
, "INBOX");
555 for (matchedchars
= 0, i
= 0;
556 regexes
[i
] != NULL
&& matchedchars
<= 0; i
++) {
557 matchedchars
= regulo_match(regexes
[i
], unaliased_str
, regulos
);
560 /* failed to match either regex */
561 if (matchedchars
<= 0) {
563 IMAP_DM(pc
, DEBUG_ERROR
, "Couldn't parse line %s (%d)\n"
564 " If this used to work, run wmbiff with the -relax option, and\n"
565 " send mail to "PACKAGE_BUGREPORT
" with the hostname\n"
566 " of your mail server.\n", unaliased_str
, matchedchars
);
570 PCU
.serverPort
= serverPort
;
572 PCU
.password_len
= strlen(PCU
.password
);
573 if (PCU
.password
[0] == '\0') {
574 PCU
.interactive_password
= 1;
576 ENFROB(PCU
.password
);
579 // grab_authList(unaliased_str + matchedchars, PCU.authList);
583 IMAP_DM(pc
, DEBUG_INFO
, "userName= '%s'\n", PCU
.userName
);
584 IMAP_DM(pc
, DEBUG_INFO
, "password is %zu characters long\n",
586 IMAP_DM(pc
, DEBUG_INFO
, "serverName= '%s'\n", PCU
.serverName
);
587 IMAP_DM(pc
, DEBUG_INFO
, "serverPath= '%s'\n", pc
->path
);
588 IMAP_DM(pc
, DEBUG_INFO
, "serverPort= '%d'\n", PCU
.serverPort
);
589 IMAP_DM(pc
, DEBUG_INFO
, "authList= '%s'\n", PCU
.authList
);
591 if (strcmp(pc
->action
, "msglst") == 0 ||
592 strcmp(pc
->fetchcmd
, "msglst") == 0 ||
593 strcmp(pc
->button2
, "msglst") == 0) {
594 PCU
.wantCacheHeaders
= 1;
596 PCU
.wantCacheHeaders
= 0;
598 pc
->checkMail
= imap_checkmail
;
599 pc
->getHeaders
= imap_getHeaders
;
600 pc
->releaseHeaders
= imap_releaseHeaders
;
604 pc
->OldUnreadMsgs
= -1;
608 static int authenticate_plaintext( /*@notnull@ */ Pop3
*pc
,
609 struct connection_state
*scs
,
610 const char *capabilities
)
613 /* is login prohibited? */
614 /* "An IMAP client which complies with [rfc2525, section 3.2]
615 * MUST NOT issue the LOGIN command if this capability is present.
617 if (strstr(capabilities
, "LOGINDISABLED")) {
618 IMAP_DM(pc
, DEBUG_ERROR
,
619 "Plaintext auth prohibited by server: (LOGINDISABLED).\n");
620 goto plaintext_failed
;
623 ask_user_for_password(pc
, 0);
626 DEFROB(PCU
.password
);
627 tlscomm_printf(scs
, "a001 LOGIN %s \"%s\"\r\n", PCU
.userName
,
629 ENFROB(PCU
.password
);
630 if (tlscomm_expect(scs
, "a001 ", buf
, BUF_SIZE
) == 0) {
631 IMAP_DM(pc
, DEBUG_ERROR
,
632 "Did not get a response to the LOGIN command.\n");
633 goto plaintext_failed
;
637 IMAP_DM(pc
, DEBUG_ERROR
, "IMAP Login failed: %s\n", buf
);
638 /* if we're prompting the user, ask again, else fail */
639 if (PCU
.interactive_password
) {
640 PCU
.password
[0] = '\0';
641 ask_user_for_password(pc
, 1); /* 1=overwrite the cache */
643 goto plaintext_failed
;
657 authenticate_md5(Pop3
*pc
,
658 struct connection_state
*scs
, const char *capabilities
)
666 if (!strstr(capabilities
, "AUTH=CRAM-MD5")) {
667 /* server doesn't support cram-md5. */
671 tlscomm_printf(scs
, "a007 AUTHENTICATE CRAM-MD5\r\n");
672 if (tlscomm_expect(scs
, "+ ", buf
, BUF_SIZE
) == 0)
675 Decode_Base64(buf
+ 2, buf2
);
676 IMAP_DM(pc
, DEBUG_INFO
, "CRAM-MD5 challenge: %s\n", buf2
);
678 strcpy(buf
, PCU
.userName
);
680 ask_user_for_password(pc
, 0);
681 rc
= gcry_md_open(&gmh
, GCRY_MD_MD5
, GCRY_MD_FLAG_HMAC
);
683 IMAP_DM(pc
, DEBUG_INFO
, "unable to initialize gcrypt md5\n");
686 DEFROB(PCU
.password
);
687 gcry_md_setkey(gmh
, PCU
.password
, strlen(PCU
.password
));
688 ENFROB(PCU
.password
);
689 gcry_md_write(gmh
, (unsigned char *) buf2
, strlen(buf2
));
691 md5
= gcry_md_read(gmh
, 0);
692 Bin2Hex(md5
, 16, buf2
);
696 IMAP_DM(pc
, DEBUG_INFO
, "CRAM-MD5 response: %s\n", buf
);
697 Encode_Base64(buf
, buf2
);
699 tlscomm_printf(scs
, "%s\r\n", buf2
);
700 if (tlscomm_expect(scs
, "a007 ", buf
, BUF_SIZE
) == 0)
703 if (!strncmp(buf
, "a007 OK", 7))
704 return 1; /* AUTH successful */
706 IMAP_DM(pc
, DEBUG_ERROR
,
707 "CRAM-MD5 AUTH failed for user '%s@%s:%d'\n",
708 PCU
.userName
, PCU
.serverName
, PCU
.serverPort
);
709 IMAP_DM(pc
, DEBUG_INFO
, "It said %s", buf
);
713 IMAP_DM(pc
, DEBUG_ERROR
,
714 "tlscomm_expect failed during cram-md5 auth: %s", buf
);
715 IMAP_DM(pc
, DEBUG_ERROR
, "failed to authenticate using cram-md5.");
720 static void ask_user_for_password( /*@notnull@ */ Pop3
*pc
, int bFlushCache
)
722 /* see if we already have a password, as provided in the config file, or
723 already requested from the user. */
724 if (PCU
.interactive_password
) {
725 if (strlen(PCU
.password
) == 0) {
726 /* we need to grab the password from the user. */
728 IMAP_DM(pc
, DEBUG_INFO
, "asking for password %d\n",
731 passwordFor(PCU
.userName
, PCU
.serverName
, pc
, bFlushCache
);
732 if (password
!= NULL
) {
733 if (strlen(password
) + 1 > BUF_SMALL
) {
734 DMA(DEBUG_ERROR
, "Password is too long.\n");
735 memset(PCU
.password
, 0, BUF_SMALL
- 1);
737 strncpy(PCU
.password
, password
, BUF_SMALL
- 1);
738 PCU
.password_len
= strlen(PCU
.password
);
741 ENFROB(PCU
.password
);